I am using @react-google-maps/api
with React 17.0.2 for a small project. I currently have a list of coordinates, and when I click various buttons, the map centers itself on a marker at one of those coordinates. However, a lot of the places I want to center on are "POI"s, and they already have built in markers and an info box with the correct name, address, and a link to google maps. (Seen HERE) Is it possible to make the map center on and open a specified POI? I have not found any documentation or examples of this. Simplified current code below:
const pinLocations = {
location1: { lat: 1, lng: 1 },
location2: { lat: 2, lng: 2 }
};
const Example = () => {
const { isLoaded } = useJsApiLoader({
googleMapsApiKey: API_KEY,
});
const [center, setCenter] = useState(pinLocations.location1);
function updateMap(pinLocation) {
setCenter(pinLocation);
}
return (
<GoogleMap zoom={11} position={center}>
<Marker position={center} />
</GoogleMap>
<Button onClick={() => updateMap(pinLocations.location1)}>
Location 1
</Button>
<Button onClick={() => updateMap(pinLocations.location2)}>
Location 2
</Button>
);
}
It's possible. I was able to somehow replicate what the tactile map had through reverse geocoding with @react-google-maps/api
library.
I did try to make it look like your sample above, and here's what I did:
I made a sample array of markers:
const markers = [
{
id: 1,
position: { lat: 14.5432, lng: 121.0473 }
},
{
id: 2,
position: { lat: 14.5468, lng: 121.0543 }
}
];
Inside the Map()
component, I made two hooks: One for the active marker, and also one for the infoWindow address result.
const [activeMarker, setActiveMarker] = useState(null);
const [address, setAddress] = useState("Address");
Then this is how I structured the <GoogleMap>
component:
return (
<GoogleMap
onLoad={handleOnLoad}
onClick={() => setActiveMarker(null)}
mapContainerStyle={{ width: "100vw", height: "100vh" }}
>
{/*maps the array of markers above*/}
{markers.map(({ id, position }) => (
<Marker
key={id}
position={position}
onClick={() => handleActiveMarker(position, id)}
>
{/*show the infoWindow of the Active marker*/}
{activeMarker === id ? (
<InfoWindow
onCloseClick={() => setActiveMarker(null)}
options={{ maxWidth: 200 }}
>
<div>{address}</div>
</InfoWindow>
) : null}
</Marker>
))}
</GoogleMap>
);
The functions inside the <GoogleMap>
are handleOnLoad()
(for loading the map with bounds), and handleActiveMarker
(for showing infoWindow and reverse geocoding the address inside the infoWindow).
#1
//loads the map with bounds
const handleOnLoad = (map) => {
const bounds = new google.maps.LatLngBounds();
markers.forEach(({ position }) => bounds.extend(position));
map.fitBounds(bounds);
};
#2
//function for marker onClick
const handleActiveMarker = (position, id) => {
if (id === activeMarker) {
return;
}
console.log(id);
/*this sets the current active marker
to help in what infoWindow to open*/
setActiveMarker(id);
// console.log(position);
//start a geocoder here>>
const geocoder = new google.maps.Geocoder();
// console.log(geocoder);
geocoder
.geocode({ location: position })
.then((response) => {
if (response.results[0]) {
let fullAddress = response.results[0].formatted_address;
//this changes the address default state on infoWindow
setAddress(fullAddress);
} else {
window.alert("No results found");
}
})
.catch((e) => window.alert("Geocoder failed due to: " + e));
return;
};
I did not include a setCenter programmatically because I noticed the tactile map that you were referring to did not have one. It already automatically fits the infoWindow on the viewport.
Here's a codesandbox link if you need a reproducible example: https://codesandbox.io/s/react-google-maps-api-multiple-markers-infowindow-forked-0zjogb?file=/src/Map.js
note: Use your own API Key.
Hope this helps.