split templates
This commit is contained in:
parent
6548460478
commit
9aa8da5872
22 changed files with 2980 additions and 2384 deletions
302
oedb/resources/demo/static/map_by_what.js
Normal file
302
oedb/resources/demo/static/map_by_what.js
Normal file
|
@ -0,0 +1,302 @@
|
|||
// 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 attribution control with OpenStreetMap attribution
|
||||
map.addControl(new maplibregl.AttributionControl({
|
||||
customAttribution: '© <a href="https://www.openstreetmap.org/copyright" >OpenStreetMap</a> contributors'
|
||||
}));
|
||||
|
||||
// Store all events and their types
|
||||
let allEvents = null;
|
||||
let eventTypes = new Set();
|
||||
let eventsByType = {};
|
||||
let markersByType = {};
|
||||
let colorsByType = {};
|
||||
|
||||
// Generate a color for each event type
|
||||
function getColorForType(type, index) {
|
||||
// Predefined colors for better visual distinction
|
||||
const colors = [
|
||||
'#FF5722', '#E91E63', '#9C27B0', '#673AB7', '#3F51B5',
|
||||
'#2196F3', '#03A9F4', '#00BCD4', '#009688', '#4CAF50',
|
||||
'#8BC34A', '#CDDC39', '#FFEB3B', '#FFC107', '#FF9800'
|
||||
];
|
||||
|
||||
return colors[index % colors.length];
|
||||
}
|
||||
|
||||
// Fetch events when the map is loaded
|
||||
map.on('load', function() {
|
||||
fetchEvents();
|
||||
});
|
||||
|
||||
// Function to fetch events from the API
|
||||
function fetchEvents() {
|
||||
// Update event info
|
||||
document.getElementById('event-info').innerHTML = '<p>Loading events...</p>';
|
||||
|
||||
// Fetch events from the public API - using limit=1000 to get more events
|
||||
fetch('https://api.openeventdatabase.org/event?limit=1000')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.features && data.features.length > 0) {
|
||||
// Store all events
|
||||
allEvents = data;
|
||||
|
||||
// Process events by type
|
||||
processEventsByType(data);
|
||||
|
||||
// Create filter UI
|
||||
createFilterUI();
|
||||
|
||||
// Add all events to the map initially
|
||||
addAllEventsToMap();
|
||||
|
||||
// Fit map to events bounds
|
||||
fitMapToBounds(data);
|
||||
|
||||
// Update event info
|
||||
document.getElementById('event-info').innerHTML =
|
||||
`<p>Found ${data.features.length} events across ${eventTypes.size} different types.</p>`;
|
||||
} else {
|
||||
document.getElementById('event-info').innerHTML = '<p>No events found.</p>';
|
||||
document.getElementById('filter-list').innerHTML = '<li>No event types available.</li>';
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error fetching events:', error);
|
||||
document.getElementById('event-info').innerHTML =
|
||||
`<p>Error loading events: ${error.message}</p>`;
|
||||
});
|
||||
}
|
||||
|
||||
// Process events by their "what" type
|
||||
function processEventsByType(data) {
|
||||
eventTypes = new Set();
|
||||
eventsByType = {};
|
||||
|
||||
// Group events by their "what" type
|
||||
data.features.forEach(feature => {
|
||||
const properties = feature.properties;
|
||||
const what = properties.what || 'Unknown';
|
||||
|
||||
// Add to set of event types
|
||||
eventTypes.add(what);
|
||||
|
||||
// Add to events by type
|
||||
if (!eventsByType[what]) {
|
||||
eventsByType[what] = [];
|
||||
}
|
||||
eventsByType[what].push(feature);
|
||||
});
|
||||
|
||||
// Assign colors to each type
|
||||
let index = 0;
|
||||
eventTypes.forEach(type => {
|
||||
colorsByType[type] = getColorForType(type, index);
|
||||
index++;
|
||||
});
|
||||
}
|
||||
|
||||
// Create the filter UI
|
||||
function createFilterUI() {
|
||||
const filterList = document.getElementById('filter-list');
|
||||
filterList.innerHTML = '';
|
||||
|
||||
// Sort event types alphabetically
|
||||
const sortedTypes = Array.from(eventTypes).sort();
|
||||
|
||||
// Create a checkbox for each event type
|
||||
sortedTypes.forEach(type => {
|
||||
const count = eventsByType[type].length;
|
||||
const color = colorsByType[type];
|
||||
|
||||
const li = document.createElement('li');
|
||||
li.className = 'filter-item';
|
||||
|
||||
const checkbox = document.createElement('input');
|
||||
checkbox.type = 'checkbox';
|
||||
checkbox.id = `filter-${type}`;
|
||||
checkbox.checked = true;
|
||||
checkbox.addEventListener('change', () => {
|
||||
toggleEventType(type, checkbox.checked);
|
||||
});
|
||||
|
||||
const colorDot = document.createElement('span');
|
||||
colorDot.className = 'color-dot';
|
||||
colorDot.style.backgroundColor = color;
|
||||
|
||||
const label = document.createElement('label');
|
||||
label.htmlFor = `filter-${type}`;
|
||||
label.appendChild(colorDot);
|
||||
label.appendChild(document.createTextNode(type));
|
||||
|
||||
const countSpan = document.createElement('span');
|
||||
countSpan.className = 'filter-count';
|
||||
countSpan.textContent = `(${count})`;
|
||||
label.appendChild(countSpan);
|
||||
|
||||
li.appendChild(checkbox);
|
||||
li.appendChild(label);
|
||||
filterList.appendChild(li);
|
||||
});
|
||||
|
||||
// Add event listeners for select/deselect all buttons
|
||||
document.getElementById('select-all').addEventListener('click', selectAllEventTypes);
|
||||
document.getElementById('deselect-all').addEventListener('click', deselectAllEventTypes);
|
||||
}
|
||||
|
||||
// Add all events to the map
|
||||
function addAllEventsToMap() {
|
||||
// Clear existing markers
|
||||
clearAllMarkers();
|
||||
|
||||
// Add markers for each event type
|
||||
Object.keys(eventsByType).forEach(type => {
|
||||
addEventsOfTypeToMap(type);
|
||||
});
|
||||
}
|
||||
|
||||
// Add events of a specific type to the map
|
||||
function addEventsOfTypeToMap(type) {
|
||||
if (!markersByType[type]) {
|
||||
markersByType[type] = [];
|
||||
}
|
||||
|
||||
const events = eventsByType[type];
|
||||
const color = colorsByType[type];
|
||||
|
||||
events.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>Type:</strong> ${type}</p>`;
|
||||
|
||||
// Display all properties
|
||||
popupContent += '<div style="max-height: 300px; overflow-y: auto;">';
|
||||
popupContent += '<table style="width: 100%; border-collapse: collapse;">';
|
||||
|
||||
// Sort properties alphabetically for better organization
|
||||
const sortedKeys = Object.keys(properties).sort();
|
||||
|
||||
for (const key of sortedKeys) {
|
||||
// Skip the label as it's already displayed as the title
|
||||
if (key === 'label') continue;
|
||||
|
||||
const value = properties[key];
|
||||
let displayValue;
|
||||
|
||||
// Format the value based on its type
|
||||
if (value === null || value === undefined) {
|
||||
displayValue = '<em>null</em>';
|
||||
} else if (typeof value === 'object') {
|
||||
displayValue = `<pre style="margin: 0; white-space: pre-wrap;">${JSON.stringify(value, null, 2)}</pre>`;
|
||||
} else if (typeof value === 'string' && value.startsWith('http')) {
|
||||
displayValue = `<a href="${value}" >${value}</a>`;
|
||||
} else {
|
||||
displayValue = String(value);
|
||||
}
|
||||
|
||||
popupContent += `
|
||||
<tr style="border-bottom: 1px solid #eee;">
|
||||
<td style="padding: 4px; font-weight: bold; vertical-align: top;">${key}:</td>
|
||||
<td style="padding: 4px;">${displayValue}</td>
|
||||
</tr>`;
|
||||
}
|
||||
|
||||
popupContent += '</table>';
|
||||
popupContent += '</div>';
|
||||
|
||||
popupContent += '</div>';
|
||||
|
||||
// Create popup
|
||||
const popup = new maplibregl.Popup({
|
||||
closeButton: true,
|
||||
closeOnClick: true
|
||||
}).setHTML(popupContent);
|
||||
|
||||
// Add marker with popup
|
||||
const marker = new maplibregl.Marker({
|
||||
color: color
|
||||
})
|
||||
.setLngLat(coordinates)
|
||||
.setPopup(popup)
|
||||
.addTo(map);
|
||||
|
||||
// Store marker reference
|
||||
markersByType[type].push(marker);
|
||||
});
|
||||
}
|
||||
|
||||
// Toggle visibility of events by type
|
||||
function toggleEventType(type, visible) {
|
||||
if (!markersByType[type]) return;
|
||||
|
||||
markersByType[type].forEach(marker => {
|
||||
if (visible) {
|
||||
marker.addTo(map);
|
||||
} else {
|
||||
marker.remove();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Select all event types
|
||||
function selectAllEventTypes() {
|
||||
const checkboxes = document.querySelectorAll('#filter-list input[type="checkbox"]');
|
||||
checkboxes.forEach(checkbox => {
|
||||
checkbox.checked = true;
|
||||
const type = checkbox.id.replace('filter-', '');
|
||||
toggleEventType(type, true);
|
||||
});
|
||||
}
|
||||
|
||||
// Deselect all event types
|
||||
function deselectAllEventTypes() {
|
||||
const checkboxes = document.querySelectorAll('#filter-list input[type="checkbox"]');
|
||||
checkboxes.forEach(checkbox => {
|
||||
checkbox.checked = false;
|
||||
const type = checkbox.id.replace('filter-', '');
|
||||
toggleEventType(type, false);
|
||||
});
|
||||
}
|
||||
|
||||
// Clear all markers from the map
|
||||
function clearAllMarkers() {
|
||||
Object.keys(markersByType).forEach(type => {
|
||||
if (markersByType[type]) {
|
||||
markersByType[type].forEach(marker => marker.remove());
|
||||
}
|
||||
});
|
||||
markersByType = {};
|
||||
}
|
||||
|
||||
// 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
|
||||
});
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue