fix(map): simplify filters and restore style toggle behavior

This commit is contained in:
Jürgen Mummert
2026-02-26 18:26:20 +01:00
parent 40aaa747d9
commit 621ce8dc8b
6 changed files with 141 additions and 138 deletions
+100 -111
View File
@@ -199,70 +199,6 @@ const normalizeHexColor = (value, fallback = DEFAULT_EVENT_COLOR) => {
return fallback;
};
const normalizeHexColorOrNull = (value) => {
const fallback = '__INVALID__';
const normalized = normalizeHexColor(value, fallback);
return normalized === fallback ? null : normalized;
};
const parseOrganizationColorScheme = (value) => {
const raw = String(value || '').trim();
if ('' === raw) {
return [];
}
return raw
.split(',')
.map((part) => normalizeHexColorOrNull(part))
.filter((part) => null !== part);
};
const buildOrganizationTagColorMap = (container, colors, organizationItems) => {
if (!colors.length) {
return {
byTagId: {},
fallbackColor: null,
};
}
const fallbackColor = colors[0];
const wrapperId = container.dataset.mapFilterWrapperId || '';
const wrapper = wrapperId ? document.getElementById(wrapperId) : null;
let orderedTagIds = [];
if (wrapper) {
orderedTagIds = Array.from(wrapper.querySelectorAll('[data-map-tag-filter]'))
.map((button) => String(button.dataset.mapTagFilter || '').trim())
.filter((value) => /^\d+$/.test(value));
}
if (!orderedTagIds.length) {
const seen = new Set();
organizationItems.forEach((item) => {
const firstTagId = String(item?.extra?.organizationTagIds?.[0] || '').trim();
if (/^\d+$/.test(firstTagId) && !seen.has(firstTagId)) {
seen.add(firstTagId);
orderedTagIds.push(firstTagId);
}
});
}
const byTagId = {};
orderedTagIds.forEach((tagId, index) => {
byTagId[tagId] = colors[index] || fallbackColor;
});
return {
byTagId,
fallbackColor,
};
};
const applyDefaultProjection = (map) => {
if (!map || typeof map.setProjection !== 'function') {
return;
@@ -441,21 +377,18 @@ const toFeature = (item) => ({
},
});
const initOrganizationMarkers = (map, organizationItems, organizationTagColorMap) => {
const initOrganizationMarkers = (map, organizationItems, organizationColor) => {
if (!organizationItems.length) {
return {
setActiveTagIds: () => {},
setOnlyTagId: () => {},
setAllVisible: () => {},
setVisible: () => {},
};
}
const markerEntries = organizationItems.map((item) => {
const popupHtml = popupHtmlFor(item);
const primaryTagId = String(item?.extra?.organizationTagIds?.[0] || '').trim();
const configuredColor = /^\d+$/.test(primaryTagId)
? (organizationTagColorMap?.byTagId?.[primaryTagId] || organizationTagColorMap?.fallbackColor || null)
: null;
const marker = new maplibregl.Marker(configuredColor ? { color: configuredColor } : undefined)
const marker = new maplibregl.Marker(organizationColor ? { color: organizationColor } : undefined)
.setLngLat([item.longitude, item.latitude]);
if (popupHtml) {
@@ -471,8 +404,9 @@ const initOrganizationMarkers = (map, organizationItems, organizationTagColorMap
});
return {
setActiveTagIds: (activeTagIds) => {
const activeSet = new Set(normalizeTagIds(activeTagIds));
setOnlyTagId: (activeTagId) => {
const normalizedTagId = String(activeTagId ?? '').trim();
const hasActiveTag = /^\d+$/.test(normalizedTagId);
markerEntries.forEach((entry) => {
const markerElement = entry.marker.getElement();
@@ -482,8 +416,9 @@ const initOrganizationMarkers = (map, organizationItems, organizationTagColorMap
}
const hasTags = entry.tagIds.length > 0;
const isVisible = !hasTags
|| entry.tagIds.some((tagId) => activeSet.has(tagId));
const isVisible = !hasActiveTag
|| !hasTags
|| entry.tagIds.includes(normalizedTagId);
markerElement.style.display = isVisible ? '' : 'none';
});
@@ -499,6 +434,17 @@ const initOrganizationMarkers = (map, organizationItems, organizationTagColorMap
markerElement.style.display = '';
});
},
setVisible: (isVisible) => {
markerEntries.forEach((entry) => {
const markerElement = entry.marker.getElement();
if (!markerElement) {
return;
}
markerElement.style.display = isVisible ? '' : 'none';
});
},
};
};
@@ -517,17 +463,13 @@ const bindExternalTagFilters = (container, map, organizationMarkerManager, event
const tagButtons = Array.from(wrapper.querySelectorAll('[data-map-tag-filter]'));
const collectActiveTagIds = () => tagButtons
.filter((button) => button.getAttribute('aria-pressed') === 'true')
.map((button) => String(button.dataset.mapTagFilter || '').trim())
.filter((value) => /^\d+$/.test(value));
const setButtonState = (button, isActive) => {
button.setAttribute('aria-pressed', isActive ? 'true' : 'false');
button.classList.toggle('is-active', isActive);
};
const eventToggleButton = wrapper.querySelector('[data-map-event-toggle="1"]');
const actionAll = wrapper.querySelector('[data-map-filter-action="all"]');
const setEventButtonState = (isActive) => {
if (!eventToggleButton) {
@@ -538,48 +480,80 @@ const bindExternalTagFilters = (container, map, organizationMarkerManager, event
eventToggleButton.classList.toggle('is-active', isActive);
};
const setAllButtonState = (isActive) => {
if (!actionAll) {
return;
}
actionAll.setAttribute('aria-pressed', isActive ? 'true' : 'false');
actionAll.classList.toggle('is-active', isActive);
};
let activeTagId = null;
let eventsOnly = false;
const applyFilter = () => {
if (!tagButtons.length) {
organizationMarkerManager.setAllVisible();
if (eventsOnly) {
organizationMarkerManager.setVisible(false);
setAllButtonState(false);
if (eventLayerManager) {
eventLayerManager.setVisible(true);
}
return;
}
organizationMarkerManager.setActiveTagIds(collectActiveTagIds());
organizationMarkerManager.setVisible(true);
if (activeTagId) {
organizationMarkerManager.setOnlyTagId(activeTagId);
setAllButtonState(false);
if (eventLayerManager) {
eventLayerManager.setVisible(false);
}
return;
}
organizationMarkerManager.setAllVisible();
setAllButtonState(true);
if (eventLayerManager) {
eventLayerManager.setVisible(true);
}
};
tagButtons.forEach((button) => {
button.addEventListener('click', () => {
const clickedTagId = String(button.dataset.mapTagFilter || '').trim();
if (!/^\d+$/.test(clickedTagId)) {
return;
}
const isActive = button.getAttribute('aria-pressed') === 'true';
setButtonState(button, !isActive);
activeTagId = isActive ? null : clickedTagId;
eventsOnly = false;
tagButtons.forEach((otherButton) => {
const otherTagId = String(otherButton.dataset.mapTagFilter || '').trim();
setButtonState(otherButton, !!activeTagId && otherTagId === activeTagId);
});
setEventButtonState(false);
applyFilter();
});
});
const actionAll = wrapper.querySelector('[data-map-filter-action="all"]');
const actionNone = wrapper.querySelector('[data-map-filter-action="none"]');
if (actionAll) {
actionAll.addEventListener('click', () => {
tagButtons.forEach((button) => setButtonState(button, true));
applyFilter();
if (eventLayerManager) {
setEventButtonState(true);
eventLayerManager.setVisible(true);
}
});
}
if (actionNone) {
actionNone.addEventListener('click', () => {
activeTagId = null;
eventsOnly = false;
tagButtons.forEach((button) => setButtonState(button, false));
setEventButtonState(false);
applyFilter();
if (eventLayerManager) {
setEventButtonState(false);
eventLayerManager.setVisible(false);
}
});
}
@@ -593,17 +567,30 @@ const bindExternalTagFilters = (container, map, organizationMarkerManager, event
toggleButton.setAttribute('aria-expanded', nextExpanded ? 'true' : 'false');
filterGroup.hidden = !nextExpanded;
toggleButton.textContent = nextExpanded ? 'Bereiche ausblenden' : 'Bereiche anzeigen';
toggleButton.classList.toggle('is-expanded', nextExpanded);
toggleButton.classList.toggle('is-collapsed', !nextExpanded);
wrapper.classList.toggle('is-filter-expanded', nextExpanded);
wrapper.classList.toggle('is-filter-collapsed', !nextExpanded);
});
const initiallyExpanded = toggleButton.getAttribute('aria-expanded') !== 'false';
filterGroup.hidden = !initiallyExpanded;
toggleButton.classList.toggle('is-expanded', initiallyExpanded);
toggleButton.classList.toggle('is-collapsed', !initiallyExpanded);
wrapper.classList.toggle('is-filter-expanded', initiallyExpanded);
wrapper.classList.toggle('is-filter-collapsed', !initiallyExpanded);
}
if (eventToggleButton && eventLayerManager) {
eventToggleButton.addEventListener('click', () => {
const isActive = eventToggleButton.getAttribute('aria-pressed') === 'true';
const nextActive = !isActive;
eventsOnly = !isActive;
activeTagId = null;
setEventButtonState(nextActive);
eventLayerManager.setVisible(nextActive);
tagButtons.forEach((button) => setButtonState(button, false));
setEventButtonState(eventsOnly);
applyFilter();
});
} else if (eventToggleButton) {
eventToggleButton.disabled = true;
@@ -1137,10 +1124,12 @@ const initSingleMap = (container) => {
const locationItems = items.filter((item) => item.type === 'location');
const eventItems = items.filter((item) => item.type === 'event');
const allCoordinates = items.map((item) => [item.longitude, item.latitude]);
const organizationColors = parseOrganizationColorScheme(container.dataset.mapOrganizationColors);
const organizationTagColorMap = buildOrganizationTagColorMap(container, organizationColors, organizationItems);
const organizationColor = normalizeHexColor(
container.dataset.mapOrganizationColor,
eventColor,
);
const organizationMarkerManager = initOrganizationMarkers(map, organizationItems, organizationTagColorMap);
const organizationMarkerManager = initOrganizationMarkers(map, organizationItems, organizationColor);
const locationLayerManager = initLocationLayers(map, locationItems, eventColor);
let eventLayerManager = null;