Feature: Standort per Klick auf der Karte auswaehlen

Neuer Toolbar-Button "Standort auf Karte waehlen" ergaenzt die
bestehenden Wege (Browser-Geolocation, manuelle Eingabe): aktiviert
einen Auswahlmodus (Crosshair-Cursor, Hinweisleiste mit
Abbrechen-Option), der naechste Klick auf die Karte setzt
state.userLocation auf die geklickten Koordinaten. Escape oder der
Abbrechen-Button beenden den Modus ohne Aenderung.

js/map/mapController.js: startLocationPicking()/stopLocationPicking()/
isPickingLocation() kapseln den einmaligen Klick-Listener und dessen
Aufraeumen. Wiederverwendet den bereits vorhandenen
"Hier bist du"-Marker (aus dem vorherigen Fix) fuer die Anzeige.
This commit is contained in:
2026-07-24 12:55:04 +02:00
parent c7e3246b44
commit 2d41bce063
5 changed files with 157 additions and 1 deletions
+5
View File
@@ -60,6 +60,11 @@
align-items: center; align-items: center;
} }
.btn--active {
background: var(--color-primary);
color: #fff;
}
.btn--danger { .btn--danger {
background: var(--color-danger); background: var(--color-danger);
color: #fff; color: #fff;
+35
View File
@@ -51,6 +51,41 @@
background: var(--color-border); background: var(--color-border);
} }
.map-panel__map--picking {
cursor: crosshair;
}
.map-picking-hint {
position: absolute;
top: calc(var(--space-sm) + 40px);
left: var(--space-sm);
z-index: 1000;
display: flex;
align-items: center;
gap: var(--space-sm);
background: var(--color-surface);
color: var(--color-primary-dark);
padding: var(--space-sm) var(--space-md);
border-radius: var(--radius-sm);
box-shadow: var(--shadow-card);
font-size: 0.85rem;
}
.map-picking-hint[hidden] {
display: none;
}
.map-picking-hint__cancel {
flex-shrink: 0;
border: none;
background: transparent;
color: var(--color-primary-dark);
font-weight: 600;
text-decoration: underline;
cursor: pointer;
padding: 0;
}
.list-panel { .list-panel {
padding: var(--space-md); padding: var(--space-md);
overflow-y: auto; overflow-y: auto;
+10
View File
@@ -48,6 +48,9 @@
<button id="manual-location-btn" type="button" class="btn btn--secondary"> <button id="manual-location-btn" type="button" class="btn btn--secondary">
Standort manuell eingeben Standort manuell eingeben
</button> </button>
<button id="pick-location-btn" type="button" class="btn btn--secondary">
📍 Standort auf Karte wählen
</button>
<button id="add-place-btn" type="button" class="btn btn--primary"> <button id="add-place-btn" type="button" class="btn btn--primary">
+ Neues Ausflugsziel hinzufügen + Neues Ausflugsziel hinzufügen
</button> </button>
@@ -58,6 +61,13 @@
📥 KI-Ausflugsziele importieren 📥 KI-Ausflugsziele importieren
</button> </button>
</div> </div>
<p id="map-picking-hint" class="map-picking-hint" hidden>
Klicke auf die Karte, um den Standort auszuwählen.
<button id="map-picking-cancel-btn" type="button" class="map-picking-hint__cancel">
Abbrechen
</button>
</p>
<div id="map" class="map-panel__map"> <div id="map" class="map-panel__map">
<p class="map-panel__loading">Karte wird geladen…</p> <p class="map-panel__loading">Karte wird geladen…</p>
</div> </div>
+53 -1
View File
@@ -2,7 +2,14 @@
(function () { (function () {
const { initStore } = EventMap.store; const { initStore } = EventMap.store;
const { initMap, centerOnCoords, requestUserLocation } = EventMap.map; const {
initMap,
centerOnCoords,
requestUserLocation,
startLocationPicking,
stopLocationPicking,
isPickingLocation,
} = EventMap.map;
const { const {
initList, initList,
initDetail, initDetail,
@@ -76,6 +83,50 @@
}); });
} }
function setupPickLocationButton() {
const button = document.getElementById('pick-location-btn');
const hint = document.getElementById('map-picking-hint');
const cancelBtn = document.getElementById('map-picking-cancel-btn');
if (!button || !hint || !cancelBtn) return;
const defaultLabel = button.textContent;
function endPicking() {
button.textContent = defaultLabel;
button.classList.remove('btn--active');
hint.hidden = true;
}
function beginPicking() {
button.textContent = 'Klicke auf die Karte …';
button.classList.add('btn--active');
hint.hidden = false;
startLocationPicking({
onPick: ({ lat, lng }) => {
EventMap.store.setState({ userLocation: { lat, lng } });
EventMap.store.updateSettings({ userConsentGeo: true });
endPicking();
},
onCancel: endPicking,
});
}
button.addEventListener('click', () => {
if (isPickingLocation()) {
stopLocationPicking();
endPicking();
} else {
beginPicking();
}
});
cancelBtn.addEventListener('click', () => {
stopLocationPicking();
endPicking();
});
}
function setupAddPlaceButton() { function setupAddPlaceButton() {
const button = document.getElementById('add-place-btn'); const button = document.getElementById('add-place-btn');
if (!button) return; if (!button) return;
@@ -115,6 +166,7 @@
initImport('import-modal'); initImport('import-modal');
setupGeolocationButton(); setupGeolocationButton();
setupManualLocationButton(); setupManualLocationButton();
setupPickLocationButton();
setupAddPlaceButton(); setupAddPlaceButton();
setupPromptGeneratorButton(); setupPromptGeneratorButton();
setupImportButton(); setupImportButton();
+54
View File
@@ -102,6 +102,57 @@
return map; return map;
} }
let pickingActive = false;
let pickingClickHandler = null;
let pickingEscHandler = null;
/**
* Aktiviert den "Standort auf Karte wählen"-Modus: der nächste Klick auf
* die Karte liefert die geklickten Koordinaten an onPick. Escape oder ein
* erneuter Aufruf von stopLocationPicking() bricht ab (onCancel).
* @param {{onPick?: (loc:{lat:number,lng:number}) => void, onCancel?: () => void}} [handlers]
*/
function startLocationPicking({ onPick, onCancel } = {}) {
if (!map || pickingActive) return;
pickingActive = true;
map.getContainer().classList.add('map-panel__map--picking');
pickingClickHandler = (event) => {
const { lat, lng } = event.latlng;
stopLocationPicking();
if (onPick) onPick({ lat, lng });
};
map.once('click', pickingClickHandler);
pickingEscHandler = (event) => {
if (event.key === 'Escape') {
stopLocationPicking();
if (onCancel) onCancel();
}
};
document.addEventListener('keydown', pickingEscHandler);
}
/** Beendet den Standort-Auswahlmodus, ohne onPick/onCancel selbst aufzurufen. */
function stopLocationPicking() {
if (!pickingActive || !map) return;
pickingActive = false;
map.getContainer().classList.remove('map-panel__map--picking');
if (pickingClickHandler) {
map.off('click', pickingClickHandler);
pickingClickHandler = null;
}
if (pickingEscHandler) {
document.removeEventListener('keydown', pickingEscHandler);
pickingEscHandler = null;
}
}
function isPickingLocation() {
return pickingActive;
}
/** Initialisiert die Karte im Element mit der übergebenen id. */ /** Initialisiert die Karte im Element mit der übergebenen id. */
function initMap(containerId) { function initMap(containerId) {
// Leaflet leert den Container beim Initialisieren nicht selbst - den // Leaflet leert den Container beim Initialisieren nicht selbst - den
@@ -175,5 +226,8 @@
EventMap.map.centerOnPlace = centerOnPlace; EventMap.map.centerOnPlace = centerOnPlace;
EventMap.map.centerOnCoords = centerOnCoords; EventMap.map.centerOnCoords = centerOnCoords;
EventMap.map.getMapInstance = getMapInstance; EventMap.map.getMapInstance = getMapInstance;
EventMap.map.startLocationPicking = startLocationPicking;
EventMap.map.stopLocationPicking = stopLocationPicking;
EventMap.map.isPickingLocation = isPickingLocation;
EventMap.map.initMap = initMap; EventMap.map.initMap = initMap;
})(); })();