diff --git a/contao/templates/frontend/event_map.html.twig b/contao/templates/frontend/event_map.html.twig
index 8608892..8b7f177 100644
--- a/contao/templates/frontend/event_map.html.twig
+++ b/contao/templates/frontend/event_map.html.twig
@@ -107,4 +107,4 @@
-
+
diff --git a/public/assets/map-module.js b/public/assets/map-module.js
index cabdcdc..2208f02 100644
--- a/public/assets/map-module.js
+++ b/public/assets/map-module.js
@@ -532,6 +532,7 @@ const bindExternalTagFilters = (container, map, organizationMarkerManager, event
const eventToggleButton = wrapper.querySelector('[data-map-event-toggle="1"]');
const canFilterByTag = tagButtons.length > 0;
const canFilterByEvents = !!eventToggleButton;
+ const canToggleEvents = !!(eventToggleButton && eventLayerManager);
const setEventButtonState = (isActive) => {
if (!eventToggleButton) {
@@ -549,6 +550,26 @@ const bindExternalTagFilters = (container, map, organizationMarkerManager, event
let activeTagId = null;
let eventsOnly = false;
+ const updateExclusiveButtonAccessibility = () => {
+ tagButtons.forEach((button) => {
+ const isActive = button.getAttribute('aria-pressed') === 'true';
+ button.setAttribute('aria-disabled', isActive ? 'true' : 'false');
+ });
+
+ if (!eventToggleButton) {
+ return;
+ }
+
+ if (!canToggleEvents) {
+ eventToggleButton.setAttribute('aria-disabled', 'true');
+
+ return;
+ }
+
+ const isEventActive = eventToggleButton.getAttribute('aria-pressed') === 'true';
+ eventToggleButton.setAttribute('aria-disabled', isEventActive ? 'true' : 'false');
+ };
+
const applyFilter = () => {
if (eventsOnly) {
organizationMarkerManager.setVisible(false);
@@ -581,14 +602,17 @@ const bindExternalTagFilters = (container, map, organizationMarkerManager, event
tagButtons.forEach((button) => {
button.addEventListener('click', () => {
+ if (button.getAttribute('aria-disabled') === 'true') {
+ return;
+ }
+
const clickedTagId = String(button.dataset.mapTagFilter || '').trim();
if (!/^\d+$/.test(clickedTagId)) {
return;
}
- const isActive = button.getAttribute('aria-pressed') === 'true';
- activeTagId = isActive ? null : clickedTagId;
+ activeTagId = clickedTagId;
eventsOnly = false;
tagButtons.forEach((otherButton) => {
@@ -597,6 +621,7 @@ const bindExternalTagFilters = (container, map, organizationMarkerManager, event
});
setEventButtonState(false);
+ updateExclusiveButtonAccessibility();
applyFilter();
});
});
@@ -628,12 +653,16 @@ const bindExternalTagFilters = (container, map, organizationMarkerManager, event
if (eventToggleButton && eventLayerManager) {
eventToggleButton.addEventListener('click', () => {
- const isActive = eventToggleButton.getAttribute('aria-pressed') === 'true';
- eventsOnly = !isActive;
+ if (eventToggleButton.getAttribute('aria-disabled') === 'true') {
+ return;
+ }
+
+ eventsOnly = true;
activeTagId = null;
tagButtons.forEach((button) => setButtonState(button, false));
setEventButtonState(eventsOnly);
+ updateExclusiveButtonAccessibility();
applyFilter();
});
} else if (eventToggleButton) {
@@ -711,9 +740,11 @@ const bindExternalTagFilters = (container, map, organizationMarkerManager, event
setButtonState(button, null !== activeTagId && tagId === activeTagId);
});
setEventButtonState(eventsOnly);
+ updateExclusiveButtonAccessibility();
};
applyInitialDisplayMode();
+ updateExclusiveButtonAccessibility();
applyFilter();
applyMapStyleMode();
};
@@ -748,6 +779,7 @@ const initLocationLayers = (map, locationItems, markerImageId) => {
},
paint: {
'icon-opacity': 1,
+ 'icon-translate': [0, 4],
},
});
@@ -831,19 +863,9 @@ const initLocationLayers = (map, locationItems, markerImageId) => {
const initEventLayers = (map, eventItems, eventColor, markerImageId, clusterMarkerImageId) => {
const sourceId = 'eventmanager-events-source';
const clusterLayerId = EVENT_CLUSTER_LAYER_ID;
- const clusterSpiderfyLayerId = EVENT_CLUSTER_SPIDERFY_LAYER_ID;
const unclusteredLayerId = EVENT_UNCLUSTERED_LAYER_ID;
- const spiderfyHitAreaImageId = 'eventmanager-spiderfy-hit-area';
const features = eventItems.map(toFeature);
- if (!map.hasImage(spiderfyHitAreaImageId)) {
- map.addImage(spiderfyHitAreaImageId, {
- width: 1,
- height: 1,
- data: new Uint8Array([0, 0, 0, 0]),
- });
- }
-
map.addSource(sourceId, {
type: 'geojson',
data: {
@@ -875,25 +897,10 @@ const initEventLayers = (map, eventItems, eventColor, markerImageId, clusterMark
},
paint: {
'icon-opacity': 1,
+ 'icon-translate': [0, 4],
'text-color': '#FFFFFF',
'text-opacity': 1,
- },
- });
-
- map.addLayer({
- id: clusterSpiderfyLayerId,
- type: 'symbol',
- source: sourceId,
- filter: ['has', 'point_count'],
- layout: {
- 'icon-image': spiderfyHitAreaImageId,
- 'icon-size': 36,
- 'icon-anchor': 'bottom',
- 'icon-offset': [0, -1.0],
- 'icon-allow-overlap': true,
- },
- paint: {
- 'icon-opacity': 0,
+ 'text-translate': [0, 4],
},
});
@@ -911,6 +918,7 @@ const initEventLayers = (map, eventItems, eventColor, markerImageId, clusterMark
},
paint: {
'icon-opacity': 1,
+ 'icon-translate': [0, 4],
},
});
@@ -1016,7 +1024,7 @@ const initEventLayers = (map, eventItems, eventColor, markerImageId, clusterMark
},
spiderLeavesPaint: {
'icon-opacity': 1,
- 'icon-translate': [0, 8],
+ 'icon-translate': [0, 9],
},
onLeafClick: (feature, spiderEvent) => {
const clickCoordinates = spiderEvent?.lngLat
@@ -1048,14 +1056,6 @@ const initEventLayers = (map, eventItems, eventColor, markerImageId, clusterMark
map.getCanvas().style.cursor = '';
});
- const setLayerLayoutVisibility = (layerId, isVisible) => {
- if (!map.getLayer(layerId)) {
- return;
- }
-
- map.setLayoutProperty(layerId, 'visibility', isVisible ? 'visible' : 'none');
- };
-
const fadeLayerOpacity = (layerId, property, value, duration = EVENT_FADE_DURATION_MS) => {
if (!map.getLayer(layerId)) {
return;
@@ -1067,14 +1067,31 @@ const initEventLayers = (map, eventItems, eventColor, markerImageId, clusterMark
const eventLayerIds = [
clusterLayerId,
- clusterSpiderfyLayerId,
unclusteredLayerId,
];
+ const clusterFilter = ['has', 'point_count'];
+ const unclusteredFilter = ['!', ['has', 'point_count']];
+ const hiddenFilter = ['has', '__eventmanager_hidden__'];
+ let hideLayersTimeoutId = null;
+
+ const setLayerFilter = (layerId, filter) => {
+ if (!map.getLayer(layerId)) {
+ return;
+ }
+
+ map.setFilter(layerId, filter);
+ };
return {
setVisible: (isVisible) => {
if (isVisible) {
- eventLayerIds.forEach((layerId) => setLayerLayoutVisibility(layerId, true));
+ if (null !== hideLayersTimeoutId) {
+ window.clearTimeout(hideLayersTimeoutId);
+ hideLayersTimeoutId = null;
+ }
+
+ setLayerFilter(clusterLayerId, clusterFilter);
+ setLayerFilter(unclusteredLayerId, unclusteredFilter);
fadeLayerOpacity(clusterLayerId, 'icon-opacity', 1);
fadeLayerOpacity(clusterLayerId, 'text-opacity', 1);
@@ -1083,16 +1100,22 @@ const initEventLayers = (map, eventItems, eventColor, markerImageId, clusterMark
return;
}
- if (spiderfyInstance && typeof spiderfyInstance.unspiderfyAll === 'function') {
- spiderfyInstance.unspiderfyAll();
+ if (spiderfyInstance) {
+ if (typeof spiderfyInstance._clearSpiderifiedCluster === 'function') {
+ spiderfyInstance._clearSpiderifiedCluster();
+ } else if (typeof spiderfyInstance.unspiderfyAll === 'function') {
+ spiderfyInstance.unspiderfyAll();
+ }
}
fadeLayerOpacity(clusterLayerId, 'icon-opacity', 0);
fadeLayerOpacity(clusterLayerId, 'text-opacity', 0);
fadeLayerOpacity(unclusteredLayerId, 'icon-opacity', 0);
- window.setTimeout(() => {
- eventLayerIds.forEach((layerId) => setLayerLayoutVisibility(layerId, false));
+ hideLayersTimeoutId = window.setTimeout(() => {
+ setLayerFilter(clusterLayerId, hiddenFilter);
+ setLayerFilter(unclusteredLayerId, hiddenFilter);
+ hideLayersTimeoutId = null;
}, EVENT_FADE_DURATION_MS + 10);
},
};