Fix: Nutzerstandort auf der Karte anzeigen
Behebt Gitea Issue #2 "Standort auf Karte anzeigen": der per Browser-Geolocation ermittelte oder manuell eingegebene Standort (state.userLocation) wurde bisher nur zum Zentrieren/Entfernungsfilter verwendet, aber nie selbst auf der Karte dargestellt. Neuer, nicht interaktiver "Hier bist du"-Marker (blauer Punkt mit Puls-Ring, js/map/markers.js: createUserLocationMarker()) wird direkt auf die Karte gelegt (ausserhalb der clusterGroup, damit er nie mit Ausflugsziel-Markern geclustert wird) und reagiert reaktiv auf Aenderungen von state.userLocation in js/map/mapController.js.
This commit is contained in:
@@ -148,6 +148,51 @@
|
|||||||
border: 2px solid #fff;
|
border: 2px solid #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* "Hier bist du"-Marker für den übermittelten/manuell eingegebenen
|
||||||
|
Nutzerstandort (Gitea Issue #2 "Standort auf Karte anzeigen"). */
|
||||||
|
|
||||||
|
.eventmap-user-marker {
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.eventmap-user-marker__dot {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
margin: -7px 0 0 -7px;
|
||||||
|
background: #1a73e8;
|
||||||
|
border: 2px solid #fff;
|
||||||
|
border-radius: 50%;
|
||||||
|
box-shadow: var(--shadow-card);
|
||||||
|
}
|
||||||
|
|
||||||
|
.eventmap-user-marker__pulse {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
width: 22px;
|
||||||
|
height: 22px;
|
||||||
|
margin: -11px 0 0 -11px;
|
||||||
|
background: rgba(26, 115, 232, 0.35);
|
||||||
|
border-radius: 50%;
|
||||||
|
animation: eventmap-user-marker-pulse 2s ease-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes eventmap-user-marker-pulse {
|
||||||
|
0% {
|
||||||
|
transform: scale(0.6);
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: scale(1.8);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Karten-Popup */
|
/* Karten-Popup */
|
||||||
|
|
||||||
.eventmap-popup {
|
.eventmap-popup {
|
||||||
|
|||||||
+40
-2
@@ -4,16 +4,18 @@
|
|||||||
|
|
||||||
(function () {
|
(function () {
|
||||||
const { DEFAULT_MAP_CENTER } = EventMap.config;
|
const { DEFAULT_MAP_CENTER } = EventMap.config;
|
||||||
const { subscribe, setState, getFilteredPlaces } = EventMap.store;
|
const { subscribe, getState, setState, getFilteredPlaces } = EventMap.store;
|
||||||
const { getPlaceLatLng } = EventMap.models;
|
const { getPlaceLatLng } = EventMap.models;
|
||||||
const { createMarkerForPlace } = EventMap.map;
|
const { createMarkerForPlace, createUserLocationMarker } = EventMap.map;
|
||||||
|
|
||||||
let map = null;
|
let map = null;
|
||||||
let clusterGroup = null;
|
let clusterGroup = null;
|
||||||
|
let userLocationMarker = null;
|
||||||
const markersByPlaceId = new Map();
|
const markersByPlaceId = new Map();
|
||||||
|
|
||||||
let lastFilteredKey = null;
|
let lastFilteredKey = null;
|
||||||
let lastSelectedPlaceId = null;
|
let lastSelectedPlaceId = null;
|
||||||
|
let lastUserLocationKey = null;
|
||||||
|
|
||||||
/** Günstiger Vergleichsschlüssel für eine gefilterte Trefferliste (Reihenfolge + IDs). */
|
/** Günstiger Vergleichsschlüssel für eine gefilterte Trefferliste (Reihenfolge + IDs). */
|
||||||
function computeFilteredKey(places) {
|
function computeFilteredKey(places) {
|
||||||
@@ -72,6 +74,30 @@
|
|||||||
map.setView([lat, lng], zoom);
|
map.setView([lat, lng], zoom);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Zeigt den übermittelten/manuell eingegebenen Nutzerstandort als eigenen
|
||||||
|
* Marker auf der Karte an (Gitea Issue #2). Läuft außerhalb der
|
||||||
|
* clusterGroup, damit er nie mit Ausflugsziel-Markern geclustert wird und
|
||||||
|
* immer sichtbar bleibt.
|
||||||
|
*/
|
||||||
|
function renderUserLocation(userLocation) {
|
||||||
|
if (!userLocation) {
|
||||||
|
if (userLocationMarker) {
|
||||||
|
map.removeLayer(userLocationMarker);
|
||||||
|
userLocationMarker = null;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { lat, lng } = userLocation;
|
||||||
|
if (userLocationMarker) {
|
||||||
|
userLocationMarker.setLatLng([lat, lng]);
|
||||||
|
} else {
|
||||||
|
userLocationMarker = createUserLocationMarker(lat, lng);
|
||||||
|
userLocationMarker.addTo(map);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function getMapInstance() {
|
function getMapInstance() {
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
@@ -111,6 +137,10 @@
|
|||||||
fitToPlaces(initialFiltered);
|
fitToPlaces(initialFiltered);
|
||||||
lastFilteredKey = computeFilteredKey(initialFiltered);
|
lastFilteredKey = computeFilteredKey(initialFiltered);
|
||||||
|
|
||||||
|
const initialUserLocation = getState().userLocation;
|
||||||
|
renderUserLocation(initialUserLocation);
|
||||||
|
lastUserLocationKey = initialUserLocation ? `${initialUserLocation.lat},${initialUserLocation.lng}` : null;
|
||||||
|
|
||||||
subscribe((state) => {
|
subscribe((state) => {
|
||||||
// Filter/Standort können sich ändern, ohne dass sich state.places
|
// Filter/Standort können sich ändern, ohne dass sich state.places
|
||||||
// ändert - daher bei jeder Store-Änderung neu filtern und nur bei
|
// ändert - daher bei jeder Store-Änderung neu filtern und nur bei
|
||||||
@@ -128,6 +158,14 @@
|
|||||||
centerOnPlace(state.selectedPlaceId);
|
centerOnPlace(state.selectedPlaceId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const userLocationKey = state.userLocation
|
||||||
|
? `${state.userLocation.lat},${state.userLocation.lng}`
|
||||||
|
: null;
|
||||||
|
if (userLocationKey !== lastUserLocationKey) {
|
||||||
|
lastUserLocationKey = userLocationKey;
|
||||||
|
renderUserLocation(state.userLocation);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return map;
|
return map;
|
||||||
|
|||||||
@@ -60,5 +60,34 @@
|
|||||||
return marker;
|
return marker;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let userLocationIcon = null;
|
||||||
|
|
||||||
|
function getUserLocationIcon() {
|
||||||
|
if (!userLocationIcon) {
|
||||||
|
userLocationIcon = L.divIcon({
|
||||||
|
className: 'eventmap-user-marker',
|
||||||
|
html: '<span class="eventmap-user-marker__pulse"></span><span class="eventmap-user-marker__dot"></span>',
|
||||||
|
iconSize: [22, 22],
|
||||||
|
iconAnchor: [11, 11],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return userLocationIcon;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Erzeugt einen (nicht klickbaren) Marker für den übermittelten/manuell
|
||||||
|
* eingegebenen Nutzerstandort (Gitea Issue #2 "Standort auf Karte
|
||||||
|
* anzeigen"). Bewusst kein Popup/Interaktion, da es kein Ausflugsziel ist.
|
||||||
|
*/
|
||||||
|
function createUserLocationMarker(lat, lng) {
|
||||||
|
return L.marker([lat, lng], {
|
||||||
|
icon: getUserLocationIcon(),
|
||||||
|
interactive: false,
|
||||||
|
keyboard: false,
|
||||||
|
zIndexOffset: 1000,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
EventMap.map.createMarkerForPlace = createMarkerForPlace;
|
EventMap.map.createMarkerForPlace = createMarkerForPlace;
|
||||||
|
EventMap.map.createUserLocationMarker = createUserLocationMarker;
|
||||||
})();
|
})();
|
||||||
|
|||||||
Reference in New Issue
Block a user