import { ControlPosition, useMap } from "react-map-gl/mapbox-legacy"; import MapboxGeocoder, { Result } from "@mapbox/mapbox-gl-geocoder"; import { useEffect, useState } from "react"; // export interface GeocoderObject { // id: string; // place_name: string; // center: number[]; // place_type: string[]; // } // interface GeocoderResult { // result: GeocoderObject; // } interface Props { mapboxAccessToken: string; position: ControlPosition; customEntries?: Result[]; customTransition?: (objectResult: Result) => void; resultFunction?: (objectResult: Result) => void; } //const MAPBOX_TOKEN = process.env.REACT_APP_MAPBOX_ACCESS_TOKEN; // const MAPBOX_TOKEN = import.meta.env.VITE_MAPBOX_ACCESS_TOKEN; // const geoCoder = new MapboxGeocoder({ // accessToken: MAPBOX_TOKEN ?? "", // flyTo: true, // marker: false, // zoom: 18 // }); export default function Geocoder(props: Props) { const { mapboxAccessToken, position, customEntries, resultFunction, customTransition } = props; const [geoCoder, setGeoCoder] = useState() const { current: map } = useMap(); const localSearch = (query: string) => { const matchesCoords = query.match( /^[ ]*(?:Lat: )?(-?\d+\.?\d*)[, ]+(?:Lng: )?(-?\d+\.?\d*)[ ]*$/i ); let matchingResults: Result[] = []; if (matchesCoords) { const coord1 = Number(matchesCoords[1]); const coord2 = Number(matchesCoords[2]); const matchingCoords: Result[] = []; if (coord1 < -90 || coord1 > 90) { // coord1 is longitude matchingCoords.push({ id: "Lat: " + coord2 + " Lng: " + coord1, place_name: "Lat: " + coord2 + " Lng: " + coord1, center: [coord1, coord2], place_type: ["coordinate"] } as Result); } if (coord2 < -90 || coord2 > 90) { // coord2 is longitude matchingCoords.push({ id: "Lat: " + coord1 + " Lng: " + coord2, place_name: "Lat: " + coord1 + " Lng: " + coord2, center: [coord2, coord1], place_type: ["coordinate"] } as Result); } if (matchingCoords.length === 0) { // else could be either lng, lat or lat, lng matchingCoords.push({ id: "Lat: " + coord2 + " Lng: " + coord1, place_name: "Lat: " + coord2 + " Lng: " + coord1, center: [coord1, coord2], place_type: ["coordinate"] } as Result); matchingCoords.push({ id: "Lat: " + coord1 + " Lng: " + coord2, place_name: "Lat: " + coord1 + " Lng: " + coord2, center: [coord2, coord1], place_type: ["coordinate"] } as Result); } matchingResults = matchingResults.concat(matchingCoords); } customEntries?.forEach(obj => { if (obj.place_name.toLowerCase().includes(query.toLowerCase())) { matchingResults.push(obj); } }); return matchingResults; }; //create the geocoder useEffect(()=>{ const g = new MapboxGeocoder({ accessToken: mapboxAccessToken, localGeocoder: localSearch, flyTo: customTransition ? false : true, marker: false, zoom: 18, }); setGeoCoder(g) },[mapboxAccessToken]) // //set the geocoder options // useEffect(() => { // //connects the localSearch function to the geocoder if there are custom entries passed in // if (customEntries) { // //need to determine a new way to handle custom search with updated geocoder // //geoCoder.options.localGeocoder = localSearch; // } // //disables the transition that the geocoder would fire if a custom transition was passed in // if (customTransition) { // geoCoder.setFlyTo(false); // } // }, [customEntries, customTransition]); // eslint-disable-line react-hooks/exhaustive-deps //attach custom functions to event handlers useEffect(() => { if(geoCoder){ //event is fired when the search bar is cleared geoCoder.on("clear", () => {}); //event is fired when starting to load the results geoCoder.on("loading", () => {}); //event is fired when the results come back from a search geoCoder.on("results", () => {}); //event is fired when there is an error geoCoder.on("error", () => {}); //event is fired when an option is selected from the results geoCoder.on("result", (res: Result) => { if (resultFunction) { resultFunction(res); } if (customTransition) { customTransition(res); } }); //once the map ref and access token are set up add the control to the map if (map) { map.addControl(geoCoder, position); } } }, [map, geoCoder]); // eslint-disable-line react-hooks/exhaustive-deps return null; }