I made a Google Maps map with a draggable marker in react. When the user drags the marker, I need to know the new latitude and longitude.
How can I retrieve the new coordinates?
I don't understand what is the best approach to doing that in react.
I made a Google Maps map with a draggable marker in react. When the user drags the marker, I need to know the new latitude and longitude.
How can I retrieve the new coordinates?
I don't understand what is the best approach to doing that in react.
Here is an example of how to do that with Typescript.
Basically, you need to have a state to track the latitude and longitude. On the MarkerF component in which you import from @react-google-maps/api, you can pass in a callback function to update the lat/long when you finish dragging the marker.
type MapOptions = google.maps.MapOptions
type SearchBox = google.maps.places.SearchBox
type Map = google.maps.Map
type MapMouseEvent = google.maps.MapMouseEvent
type Props = {
lat: number
lng: number
}
/**
* Map component using Google Map API
* The map is centered at the given lat and lng initially but location can also be updated by searching with the search box
* @param {number} lat - latitude
* @param {number} lng - longitude
* @returns
*/
const Map: React.FC<Props> = ({ lat, lng }) => {
// Ref to the google map instance
const mapRef = useRef<Map>()
// Ref to the search box instance
const searchBoxRef = useRef<SearchBox>()
// Options for the Google Map
const mapOptions = useMemo<MapOptions>(() => ({}), [])
// Location lat/lng state
const [coordinates, setCoordinates] = React.useState({
lat,
lng,
})
// Handle event when the map is loaded
const onLoad = useCallback((map: Map) => {
mapRef.current = map
}, [])
// Handle event when the search box is loaded
const onSearchBoxLoad = useCallback((searchBox: SearchBox) => {
searchBoxRef.current = searchBox
}, [])
// Handle event when the location is changed
const onPlacesChanged = () => {
const searchBox = searchBoxRef.current
if (!searchBox) return
// Get the place results from the search box
const places = searchBox.getPlaces()
if (!places || places.length === 0) return
// Get the lat and lng of the first result
const lat = places[0].geometry?.location?.lat()
const lng = places[0].geometry?.location?.lng()
// Set the coordinates state
if (lat && lng) {
setCoordinates({ lat, lng })
}
}
// Handle event when the marker is dragged to a new position
const onDragEnd = (e: MapMouseEvent) => {
// Get the lat and lng of the marker at new position
const lat = e.latLng?.lat()
const lng = e.latLng?.lng()
// Update the coordinates state
if (lat && lng) {
setCoordinates({ lat, lng })
}
}
return (
<Box component="div" width="100vw" height="400px">
<GoogleMap
zoom={15}
center={{
lat: coordinates.lat,
lng: coordinates.lng,
}}
mapContainerClassName="map-container"
options={mapOptions}
onLoad={onLoad}
>
{/* NOTE - need to use MarkerF for React v18 */}
<MarkerF
position={{
lat: coordinates.lat,
lng: coordinates.lng,
}}
draggable={true}
onDragEnd={onDragEnd}
/>
<StandaloneSearchBox
onLoad={onSearchBoxLoad}
onPlacesChanged={onPlacesChanged}
>
<input
type="text"
placeholder="Customized your placeholder"
style={{
boxSizing: `border-box`,
border: `1px solid transparent`,
width: `240px`,
height: `32px`,
padding: `0 12px`,
borderRadius: `3px`,
boxShadow: `0 2px 6px rgba(0, 0, 0, 0.3)`,
fontSize: `14px`,
outline: `none`,
textOverflow: `ellipses`,
position: 'absolute',
left: '50%',
marginLeft: '-120px',
}}
/>
</StandaloneSearchBox>
</GoogleMap>
</Box>
)
}
Also, before doing this, in a parent component, you also need to have already loaded the Google Map with your API key. Here is an example
type Props = {
latitude: number
longitude: number
}
const SiteMap: React.FC<Props> = ({ latitude, longitude }) => {
// The libraries to load
const [libraries] = React.useState<
('places' | 'drawing' | 'geometry' | 'localContext' | 'visualization')[]
>(['places'])
// Load the Google Map API
const { isLoaded } = useLoadScript({
id: 'google-map-script',
googleMapsApiKey: 'YOUR_API_KEY',
libraries,
})
if (!isLoaded) return <div>Loading...</div>
return <Map lat={latitude} lng={longitude} />
}