"use client"; import { Circle, MapContainer, Marker, Polyline, Popup, TileLayer, useMapEvents, } from "react-leaflet"; import "leaflet/dist/leaflet.css"; import "leaflet-defaulticon-compatibility/dist/leaflet-defaulticon-compatibility.css"; import "leaflet-defaulticon-compatibility"; import { Home } from "lucide-react"; import { useState } from "react"; import { Marker as CustomMarker } from "~/components/map/custom_marker"; import MapMarker from "~/components/map/map_marker"; import { cn } from "~/lib/utils"; type LatLon = { lat: number; lng: number; alt?: number; }; type posData = { pos: LatLon; popupTxt?: string; onClick?: () => void; markerTxt?: string; }; type GroupProps = { isGroup: true; groupData: posData[]; }; type SingleProps = { isGroup?: false; groupData?: never; }; type MarkerType = "precise" | "circle" | "price" | "home"; type MapProps = { posix: posData; autocenter?: boolean; zoom?: number; markerType: MarkerType; markerRadius?: number; scrollWheelZoom?: boolean; width?: string; height?: string; onMapClick?: () => void; isMeasuring?: boolean; } & (GroupProps | SingleProps); const defaults = { height: "500px", width: "500px", zoom: 15, }; const MedianPoint = (pos: posData[]) => { const lat = pos.map((p) => p.pos.lat).reduce((a, b) => a + b) / pos.length; const lng = pos.map((p) => p.pos.lng).reduce((a, b) => a + b) / pos.length; return { lat, lng }; }; const MarkerComp = ({ pos, markerType, markerRadius, }: { pos: posData; markerType: MarkerType; markerRadius?: number; }) => { switch (markerType) { case "price": return ( {pos.markerTxt} } size="sm" /> } position={pos.pos} title={pos.markerTxt} > {pos.popupTxt && {pos.popupTxt}} ); case "precise": return ( {pos.popupTxt && {pos.popupTxt}} ); case "circle": return ( {pos.popupTxt && {pos.popupTxt}} ); case "home": return ( <> {pos.popupTxt && {pos.popupTxt}} } position={pos.pos} title={pos.markerTxt} > {pos.popupTxt && {pos.popupTxt}} ); default: throw new Error(`Invalid marker type: ${markerType satisfies never}`); } }; function getDistanceInKm(pos1: LatLon, pos2: LatLon) { const R = 6371; // Radius of the earth in km const dLat = deg2rad(pos2.lat - pos1.lat); const dLon = deg2rad(pos2.lng - pos1.lng); const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(deg2rad(pos1.lat)) * Math.cos(deg2rad(pos2.lat)) * Math.sin(dLon / 2) * Math.sin(dLon / 2); const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); const distance = R * c; // Distance in km return distance; } function deg2rad(deg: number) { return deg * (Math.PI / 180); } const DistanceMarker = ({ pos, posix }: { pos: LatLon; posix: posData }) => { const distanceKm = getDistanceInKm(pos, posix.pos); return ( <> ~{distanceKm.toFixed(2)} km } size="sm" /> } position={pos} title={"Distanza"} /> ); }; const MapComp = ({ posix, autocenter, zoom = defaults.zoom, markerType, markerRadius, scrollWheelZoom = false, width = defaults.width, height = defaults.height, isGroup, groupData, onMapClick, isMeasuring, }: MapProps) => { const [measuringPos, setMeasuringPos] = useState(null); const APIs = () => { useMapEvents({ click: (e) => { if (isMeasuring) { setMeasuringPos(e.latlng); return; } if (onMapClick) { onMapClick(); } }, }); return null; }; const hashKey = JSON.stringify( groupData ? groupData.map((p) => p.pos) : posix.pos, ); return ( {isGroup ? ( groupData.map((pos, i) => ( key={i} markerRadius={markerRadius} markerType={markerType} pos={pos} /> )) ) : ( )} {isMeasuring && measuringPos && ( )} ); }; export default MapComp; /* const PuntiInteresse: { title: string; lat: number; lng: number; icon: IconType; }[] = [ { title: "PIAZZA LIBERTA’", lat: 45.766706, lng: 11.733919, icon: "milestone", }, { title: "PONTE VECCHIO", lat: 45.76752, lng: 11.731148, icon: "milestone" }, { title: "INFOALLOGGI", lat: 45.764886, lng: 11.736019, icon: "info" }, { title: "PRATO 1", lat: 45.770066, lng: 11.736306, icon: "parking" }, { title: "PRATO 2", lat: 45.771495, lng: 11.734107, icon: "parking" }, { title: "STAZIONE FERROVIARIA/BUS", lat: 45.766709, lng: 11.741204, icon: "milestone", }, { title: "GIARDINI PAROLINI", lat: 45.764804, lng: 11.738355, icon: "park" }, { title: "BIBLIOTECA", lat: 45.765801, lng: 11.735987, icon: "school" }, { title: "CENTRO STUDIO", lat: 45.754266, lng: 11.733066, icon: "school" }, { title: "OSPEDALE", lat: 45.747444, lng: 11.744371, icon: "cross" }, { title: "PALARENA CMP", lat: 45.747374, lng: 11.740302, icon: "entertainment", }, { title: "PONTE NUOVO", lat: 45.764594, lng: 11.729995, icon: "milestone" }, { title: "OSSARIO ", lat: 45.763568, lng: 11.733449, icon: "milestone" }, { title: "CINEMA METROPOLIS", lat: 45.742997, lng: 11.735622, icon: "film" }, { title: "CENTRO COMMERCIALE GRIFONE", lat: 45.744988, lng: 11.751847, icon: "cart", }, { title: "CENTRO COMMERCIALE EMISFERO", lat: 45.742368, lng: 11.728874, icon: "cart", }, { title: "SUPERMERCATO Alì s. vito", lat: 45.775167, lng: 11.750929, icon: "cart", }, { title: "SUPERMERCATO Alì cà baroncello ", lat: 45.758659, lng: 11.751037, icon: "cart", }, { title: "CONAD via passalacqua", lat: 45.771366, lng: 11.742604, icon: "cart", }, { title: "CONAD VIALE PECORI GIRARDI", lat: 45.764649, lng: 11.720416, icon: "cart", }, { title: "BIOSAPORI VIALE DE GASPERI", lat: 45.761377, lng: 11.732186, icon: "cart", }, { title: "SUPERMERCATO ALDI ", lat: 45.743694, lng: 11.755435, icon: "cart" }, { title: "SUPERMERCATO TOSANO", lat: 45.764982, lng: 11.766572, icon: "cart", }, { title: "POSTE CENTRALI BASSANO", lat: 45.762758, lng: 11.735091, icon: "mail", }, { title: "POSTE VIA ANGARANO", lat: 45.767573, lng: 11.726599, icon: "mail" }, ]; */