153 lines
4.7 KiB
TypeScript
153 lines
4.7 KiB
TypeScript
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<MapboxGeocoder>()
|
|
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;
|
|
}
|