jagd-apps/stoeberhunde/frontend/src/components/map/MapView.js

96 lines
3.3 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { useEffect } from 'react';
import { MapContainer, TileLayer, Marker, Popup, Circle, useMap } from 'react-leaflet';
import L from 'leaflet';
import 'leaflet/dist/leaflet.css';
import markerIcon2x from 'leaflet/dist/images/marker-icon-2x.png';
import markerIcon from 'leaflet/dist/images/marker-icon.png';
import markerShadow from 'leaflet/dist/images/marker-shadow.png';
import './MapView.css';
// Standard-Marker-Icons aus dem installierten Leaflet-Paket buendeln.
// Vorher kamen sie von cdnjs — in einer Offline-PWA fuer den Wald waren die
// Marker damit ohne Empfang kaputt, und die IP jedes Besuchers ging an ein
// fremdes CDN. Die Dateien liegen ohnehin in leaflet/dist/images.
delete L.Icon.Default.prototype._getIconUrl;
L.Icon.Default.mergeOptions({
iconRetinaUrl: markerIcon2x,
iconUrl: markerIcon,
shadowUrl: markerShadow,
});
// Komponente zum Aktualisieren der Kartenansicht
function MapUpdater({ center, zoom }) {
const map = useMap();
useEffect(() => {
if (center && zoom) {
map.setView(center, zoom, { animate: true, duration: 0.5 });
}
}, [center, zoom, map]);
return null;
}
const MapView = ({ users, center = [52.5, 9.5], zoom = 8, userLocation = null, radiusKm = 25 }) => {
const usersWithGPS = users ? users.filter(user => user.gps && user.gps.lat && user.gps.lng) : [];
// Berechne Kartenmittelpunkt und Zoom basierend auf Benutzerposition und Radius
const mapCenter = userLocation ? [userLocation.lat, userLocation.lng] : center;
const mapZoom = userLocation ? Math.max(8, Math.min(13, Math.round(14 - Math.log2(radiusKm)))) : zoom;
return (
<div className="map-container">
<MapContainer
center={mapCenter}
zoom={mapZoom}
style={{ height: '500px', width: '100%' }}
scrollWheelZoom={true}
>
<MapUpdater center={mapCenter} zoom={mapZoom} />
<TileLayer
attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
{userLocation && (
<>
<Marker position={[userLocation.lat, userLocation.lng]}>
<Popup>
<div className="map-popup">
<h3>Ihr Standort</h3>
</div>
</Popup>
</Marker>
<Circle
center={[userLocation.lat, userLocation.lng]}
radius={radiusKm * 1000}
pathOptions={{ color: 'blue', fillColor: 'blue', fillOpacity: 0.1 }}
/>
</>
)}
{usersWithGPS.map(user => (
<Marker
key={user._id}
position={[user.gps.lat, user.gps.lng]}
>
<Popup>
<div className="map-popup">
<h3>{user.name}</h3>
<p>{user.address}</p>
<p>
<a href={`tel:${user.phone}`}>{user.phone}</a>
</p>
<p className="map-popup-type">{user.type}</p>
</div>
</Popup>
</Marker>
))}
</MapContainer>
{usersWithGPS.length === 0 && !userLocation && (
<div className="map-no-data-overlay">Keine GPS-Daten verfügbar Karte wird trotzdem angezeigt.</div>
)}
</div>
);
};
export default MapView;