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:
@@ -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;
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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();
|
||||||
|
|||||||
@@ -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;
|
||||||
})();
|
})();
|
||||||
|
|||||||
Reference in New Issue
Block a user