UNPKG

@dossierhq/leaflet

Version:

A library for rendering maps in Dossier with Leaflet.

117 lines 5.27 kB
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { control } from 'leaflet'; import 'leaflet.locatecontrol'; import { Suspense, useEffect, useRef, } from 'react'; import { MapContainer as LeafletMapContainer, Marker, TileLayer, Tooltip, useMap, useMapEvents, } from 'react-leaflet'; import { toLatLngLiteral } from './CoreTypes.js'; import { getMarkerIcon } from './MarkerUtils.js'; const defaultZoom = 13; export const MapContainer = ({ className, style, center, zoom, minZoom, resetSignal, maxBoundingBox, onBoundingBoxChanged, onZoomMetricsChanged, children, }) => { const mapRef = useRef(null); useEffect(() => { if (resetSignal && mapRef.current) { mapRef.current.setView(center, zoom ?? defaultZoom, { animate: true }); } //TODO fix dependencies // eslint-disable-next-line react-hooks/exhaustive-deps }, [resetSignal]); useEffect(() => { // Fix issue where tiles are sometimes not loaded on initial display // https://github.com/PaulLeCam/react-leaflet/issues/340 setTimeout(() => mapRef.current?.invalidateSize(), 0); }, []); return (_jsx(LeafletMapContainer, { ref: mapRef, className: className, style: style, center: center, zoom: zoom ?? defaultZoom, minZoom: minZoom, maxBounds: maxBoundingBox ? toLatLngLiteral(maxBoundingBox) : undefined, scrollWheelZoom: true, children: _jsxs(Suspense, { children: [!!onBoundingBoxChanged || !!onZoomMetricsChanged ? (_jsx(MapEventListener, { onBoundingBoxChanged: onBoundingBoxChanged, onZoomMetricsChanged: onZoomMetricsChanged })) : null, _jsx(TileLayer, { attribution: '\u00A9 <a href="http://osm.org/copyright" target="_blank" rel="noopener">OpenStreetMap</a> contributors', url: "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" }), children] }) })); }; MapContainer.displayName = 'MapContainer'; function MapEventListener({ onBoundingBoxChanged, onZoomMetricsChanged, }) { const map = useMapEvents({ ...(onBoundingBoxChanged ? { move: (_event) => { onBoundingBoxChanged(getBoundingBox(map)); }, } : {}), ...(onZoomMetricsChanged ? { zoom: (_event) => { onZoomMetricsChanged(getZoomMetrics(map)); }, } : {}), }); useEffect(() => { if (onBoundingBoxChanged) onBoundingBoxChanged(getBoundingBox(map)); if (onZoomMetricsChanged) onZoomMetricsChanged(getZoomMetrics(map)); }, [map, onBoundingBoxChanged, onZoomMetricsChanged]); return null; } function getBoundingBox(map) { const bounds = map.getBounds(); const boundingBox = { minLat: bounds.getSouth(), maxLat: bounds.getNorth(), minLng: bounds.getWest(), maxLng: bounds.getEast(), }; return boundingBox; } function getZoomMetrics(map) { const location0 = map.containerPointToLatLng([0, 0]); const location1 = map.containerPointToLatLng([1, 1]); const metrics = { pixelToLat: location0.lat - location1.lat, pixelToLng: location1.lng - location0.lng, }; return metrics; } function LocateControl({ outsideMapBoundsMsg, showPopup, autoStart, title }) { const map = useMap(); useEffect(() => { const strings = {}; if (outsideMapBoundsMsg) strings.outsideMapBoundsMsg = outsideMapBoundsMsg; if (title) strings.title = title; const locateControl = control.locate({ icon: 'icon-map-location leaflet-icon', iconLoading: 'icon-map-location leaflet-icon is-pulsing', showPopup, strings, }); map.addControl(locateControl); if (autoStart) { void navigator.permissions.query({ name: 'geolocation' }).then((result) => { if (result.state === 'granted') locateControl.start(); }); } return () => { map.removeControl(locateControl); }; }, [map, outsideMapBoundsMsg, showPopup, autoStart, title]); return null; } MapContainer.LocateControl = LocateControl; MapContainer.LocateControl.displayName = 'MapContainer.LocateControl'; function MapContainerMarker({ color, location, tooltip, onClick }) { return (_jsx(Marker, { position: [location.lat, location.lng], icon: getMarkerIcon(color), eventHandlers: onClick ? { click: onClick } : undefined, children: tooltip ? _jsx(Tooltip, { children: tooltip }) : null })); } MapContainer.Marker = MapContainerMarker; MapContainer.Marker.displayName = 'MapContainer.Marker'; function EditLocationMarker({ value, onChange }) { useMapEvents({ click: (event) => { onChange({ lat: Math.round(event.latlng.lat * 1e6) / 1e6, lng: Math.round(event.latlng.lng * 1e6) / 1e6, }); }, }); return value ? (_jsx(Marker, { position: [value.lat, value.lng], icon: getMarkerIcon('current') })) : null; } MapContainer.EditLocationMarker = EditLocationMarker; MapContainer.EditLocationMarker.displayName = 'MapContainer.EditLocationMarker'; //# sourceMappingURL=MapContainer.js.map