The best answer I have found is:
var bounds = new google.maps.LatLngBounds();
var infowindow = new google.maps.InfoWindow();
for (i = 0; i < locations.length; i++) {
var marker = new google.maps.Marker({
position: new google.maps.LatLng(locations[i][1], locations[i][2]),
map: map
});
//extend the bounds to include each marker's position
bounds.extend(marker.position);
google.maps.event.addListener(marker, 'click', (function(marker, i) {
return function() {
infowindow.setContent(locations[i][0]);
infowindow.open(map, marker);
}
})(marker, i));
}
//now fit the map to the newly inclusive bounds
map.fitBounds(bounds);
//(optional) restore the zoom level after the map is done scaling
var listener = google.maps.event.addListener(map, "idle", function () {
map.setZoom(3);
google.maps.event.removeListener(listener);
});
But how to do this with this library?
I've done this just by having a property in state called center and passing that to the map. When you click on a marker, you can just update center with the coordinates of the marker.
Helpful note here, which caused me to spend almost 1 hour in debugging: there are props defaultCenter and center on GoogleMap component. The defaultCenter doesn't seem to update even if it's changed later on, so changing this to center fixed it.
Hope this helps someone save some time in the future.
Thanks for the advice guys - I guess I was inquiring on if I have a number of markers, I'd like to set center or defaultCenter to make sure they are all on the map (say all the markers are in the UK, I don't want my center to be NYC).
@mmahalwy Have you looked at the fitBounds method in the API? You give it a list of all your markers' coordinates and it automatically sets the bounds of your map to fit them all in.
We're working on this to make it clearer.
We're also looking for maintainers. Involve in #266 to help strengthen our community!
This was closed, but was there ever an implementation into the library? It would save me a whole lot of time if someone had an example of how they dropped this functionality into the library.
@ryanhca Are you just looking for the fitBounds implementation with react-google-maps? If so, it is an exposed method that you can access via refs on the map component.
@dyyylan thanks. I'll give it a whirl.
EDIT: After digging in further, I cannot seem to find the method. I've tried binding the
@dyyylan I have same question
It's important to note that since the _actual_ map is mounted asynchronously from the react component, you may not have methods available as soon as it mounts.
So it depends on your use case for when you want to call the method, if you already have all your data when the map loads up, you can add a callback on the GoogleMap component with onTilesloaded and then use your map ref.
Here's an example that I just tested using the most recent version:
https://gist.github.com/dyyylan/a086ed46670efccace96404c8ab97ad8
Can confirm @dyyylan's method works (thanks!), though keep in mind onTilesloaded is called during every resize, pan, zoom, etc. If you need to call it exactly once on initialization, you'll have to use some hacky method like below:
onTilesloaded = () => {
this.fitBounds()
// haxxors -- make sure to only fire a single time
this.onTilesloaded = () => {}
}
Wow, this worked really well for me! Thank you. I'm now just diggin in to see if I can force the map to fit bounds, but also zoom out a little. The fit bounds sort of force it to zoom in too far.
following up. I used @agilgur5 's solution above to only call my set bounds handler once. Now my issue is that the bounds are too far zoomed in if the coords all exist in or near the same place. I'm looking to expose the "setZoom" method on the "map" ref. I can use "getZoom" but not setZoom for some reason. I'm digging in deeper
Edit/Solution
after my setBoundsHandler is done doing what it's doing, I set the state of a zoom property to whatever number I want. And on the
short snippet:
be sure to import LatLng and LatLngBounds accordingly
const { LatLng, LatLngBounds } = google.maps;
_fitTheBounds(){
const bounds = new LatLngBounds();
const {markers, ...props} = this.props;
let newBounds = [];
markers.map(m=>{
newBounds.push(new LatLng(Number(m.lat), Number(m.lng)))
})
newBounds.forEach(bound => bounds.extend(bound));
this.refs.map.fitBounds(bounds);
this._fitTheBounds = () => {}
let currentZoom = this.refs.map.getZoom();
console.log(currentZoom)
if(currentZoom > 15){
setTimeout(()=>{
this.setState({defaultZoom: 15})
}, 100)
}
}
<GoogleMap
{...this.props}
zoom={this.state.defaultZoom}
ref="map"
onTilesloaded={()=>this._fitTheBounds()}
There is a difference between defaultZoom and zoom, just like defaultValue and value on an <input /> component.
If you want to control the zoom dynamically, just use the zoom prop on the map, it will update whenever the value changes. But it does also allow the user to zoom/pan around themself without being locked into whatever value you set.
Most (in my experience anyway) of the setFoo methods are just implemented as foo as a prop on the component.
@ryanhca I am working on a similar problem for fitting map view in bounds, but I am getting inconsistent results. Do you have sample code of the component you can share by any chance? Thanks!
@Andriy-Kulak So I had this working really well, then something broke my implementation ... IDK if it was the Google api being updated or some faulty logic on my end. But I've tabled a fix for this for a little bit until I have some time to go back to it. I'll let you know what comes of it when/if I get it re-implemented.
For now I updated my code snippet above to show you what I did for the zoom. I just set the zoom to a state property and then onTilesLoaded calls the method I use to fit the bounds. Within that method I check to see what the zoom is defaulting too with the new bounds and setState if its zoomed in too far .
@ryanhca I ended up doing to a workaround for fitbounds. the google maps geometry api was also giving me trouble so I decided to take a different approach. I have two points on a map so all I need to do is to make sure the map is centered in between the two points and the zoom is appropriate.
I calculated the middle point between two points and used that a defaultCenter using geoLib npm package (geoLib.getCenter(...) . This package can actually calculate mid-point between multiple coordinates so it works well for 2+ points as well.
Then, I calculated the distance from one point to another and used that to proportionally increase/decrease my defaultZoom... using geoLib.getDistance... or you can use Pythagorean theory most people learned in high school geometry class.
@Andriy-Kulak my gist above is a complete component with fitBounds, if you needed an example of how to use it.
I'll note that on my solution, I actually added a line at the end, this.forceUpdate() due to a React nuance:
onTilesloaded = () => {
this.fitBounds()
// haxxors -- make sure to only fire a single time
this.onTilesloaded = () => {}
this.forceUpdate()
}
As I didn't change the state in my callback, it doesn't cause the React part of the view to rerender, and therefore the binding on the component onTilesloaded={this.onTilesloaded} doesn't get rebound. forceUpdate forces the stale reference to be updated.
There are likely a few alternatives to this. Also note that this is only necessary if you want it to fire exactly once. That new line isn't on production _yet_, but you can see this working/in-action here (click the "Map" button) on Yorango's Map View.
Most helpful comment
Helpful note here, which caused me to spend almost 1 hour in debugging: there are props
defaultCenterandcenteronGoogleMapcomponent. ThedefaultCenterdoesn't seem to update even if it's changed later on, so changing this tocenterfixed it.Hope this helps someone save some time in the future.