fix(map): simplify filters and restore style toggle behavior
This commit is contained in:
+100
-111
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user