I have a google map set with the Javascript API V3. It's displayed in a div with a dynamic width, as a content pane slides up when we click on a marker.
Everything works fine, but one thing: When the pane slides up, the width of the map is changed, and so the center is displaced to the right (the pane is on the left). It is really inconvienient especially for small resolutions, where you can't even see the center after the pane is open.
I've tried the 'resize' trigger, but it doesn't seem to work... Any ideas ?
Thanks a lot !
Calling resize by it self will not acheive what you need.
What you need to do is first (before a resize occurs) get the current center of the map
var currCenter = map.getCenter();
Then you need to do something like the following, after your div is resized.
google.maps.event.trigger(map, 'resize');
map.setCenter(currCenter);
Should do the trick
UPDATE 2018-05-22
With a new renderer release in version 3.32 of Maps JavaScript API the resize event is no longer a part of Map class.
The documentation states
When the map is resized, the map center is fixed
The full-screen control now preserves center.
There is no longer any need to trigger the resize event manually.
source: https://developers.google.com/maps/documentation/javascript/new-renderer
google.maps.event.trigger(map, "resize"); doesn't have any effect starting from version 3.32
First set a variable for the current center, then use a event listener to detect a resize, and thusly set center.
//Get current center
var getCen = map.getCenter();
//Use event listener for resize on window
google.maps.event.addDomListener(window, 'resize', function() {
//Set Center
map.setCenter(getCen);
});
omarello does work but I can't upvote it. You probably forgot to refer to the var that defines your center coordinates. All "resize" does is pull the divs current width and height, it does not change anything about the map--yet!
var center = new google.maps.LatLng(39.5, -98.3);
$(document).ready(function() {
$("#fullsize").click(function(e) {
e.preventDefault();
$("#map_canvas").css({
width: '1000px'});
google.maps.event.trigger(map, "resize");
map.setCenter(center);
});
});
Hy there try this ;)
On map initialization
var currentMapCenter = null;
google.maps.event.addListener(map, 'resize', function () {
currentMapCenter = map.getCenter();
});
google.maps.event.addListener(map, 'bounds_changed', function () {
if (currentMapCenter) {
// react here
map.setCenter(currentMapCenter);
}
currentMapCenter = null;
});
After this just call when tou want the map resize.
google.maps.event.trigger(map, 'resize');
Related
I have a large page of user data that is formatted for ease of use using accordion areas.
Click on the accordion control and the relevant information is shown. Click it again and it is hidden.
One of these accordions has a google map inside it with multiple pins.
When the parent accordion div is hidden bounds/zoom has no effect. When it is visible bounds/zoom works.
I can only imagine that the DOM has the collapsing parent div set to zero height and therefor Google Maps 'sees' this as zero all the way down the stack and sets bounds based on a zero height and width accordingly.
Here is a fiddle:
https://jsfiddle.net/wjebusfL/1/
The default is to have the accordion closed. When you click the open button you will see that the map contains two markers but the zoom is way off.
If you comment out the display and opacity lines in the css for .accordianarea
display: none;
opacity: 0;
You will see the accordion in an open state by default and the map bounds/zoom working OK.
Is there any way to 'force' the google map to render correctly with the accordion closed?
New answer:
After digging a little deeper, I've found that the MapOptions has a minZoom option:
minZoom (optional)
The minimum zoom level which will be displayed on the map. If omitted, or set to null, the minimum zoom from the current map type is used instead.
If we check your map_zoom() function, it's returning 8 on the first call.
If we use that 8 together with minZoom (instead of regular zoom) we'll get the desired result without calling map_zoom() a second time:
var defaultZoom = 8;
var allMarkers = new Array();
var mapOptions = {
minZoom: defaultZoom,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
Updated JSFiddle
Old answer:
Move the map_zoom() outside of map_init() so we can call it from anywhere
On $('.accordiancontrol').click, call the map_zoom() to update our zoom:
$('.accordiancontrol').click(function(){
if ($('#accordianarea' + thisId).is(":visible")) {
// Close accordianarea
}
else {
// Open accordianarea
// Update zoom
map_zoom();
}
});
Updated JSFiddle
"I can only imagine that the DOM has the collapsing parent div set to zero height and therefor Google Maps 'sees' this as zero all the way down the stack and sets bounds based on a zero height and width accordingly."
As you stated, zoom sets bounds based on a zero height and width.. What you can do is to call map_init(); on map show. That way div has height and width and map gets proper zoom bounds
$('.accordiancontrol').click(function(){
var thisId = $(this).attr('id').replace(/^\D+/g,"")
if ($('#accordianarea' + thisId).is(":visible"))
{
// Close accordianarea
}
else
{
map_init();
// Open accordianarea
}
});
I have a <google-map> inside a <app-drawer-layout>, and it works fine except the map displays a gray area to the right when the drawer is hidden.
All the discussions I've found about this issue say that the solution is to trigger the resize event of the map, but it doesn't work for me. I even tried adding a delay just to be on the safe side, but still it does nothing.
document.querySelector('app-drawer').addEventListener('app-drawer-transitioned', function(){
window.setTimeout(function(){
console.log( map.clientWidth );
google.maps.event.trigger(map, 'resize');
}, 100);
});
The console output confirms that the map width has indeed changed before triggering the resize event, but the gray area persists. Even if I pan and zoom the map, the gray area is still there (although it becomes wider or narrower depending on the pan). The only thing that seems to correct it is resizing the entire browser window.
This is in Chrome on Mac btw.
Turns out that I was trying to trigger the resize event on the DOM-element instead of the Maps API object. The Maps API object can be obtained via the .map property of the <google-map> DOM-element.
This works for me
<script>
var mapElem = document.querySelector('google-map');
mapElem.addEventListener('api-load', function(e) {
var mapObj = mapElem.map;
document.querySelector('app-drawer').addEventListener('app-drawer-transitioned', function(){
google.maps.event.trigger(mapObj, 'resize');
});
});
</script>
I'm using ajax to load (into a div) the page that includes the Google map, however when it's finished loading it shows only a grey background for the map, with a Google logo in the bottom left, and a "Terms of use" link in the bottom right.
If I resize the window, then the map instantly appears. Also if I reload the entire page by pressing F5 the map loads normally. It's only when I initially load this map page using jQuery ajax that I get the grey map.
On the container page I load the maps api.
<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?sensor=false"></script>
On the map page I do everything else.
$(document).ready(function() {
initializeMap();
});
function initializeMap() {
var companyname = document.getElementById("companyname").value;
infowindow = new google.maps.InfoWindow();
latlng = new google.maps.LatLng(-34.397, 150.644);
var mapOptions = {
zoom: 13,
center: latlng,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
geo = new google.maps.Geocoder();
map = new google.maps.Map(document.getElementById("map-canvas"), mapOptions);
bounds = new google.maps.LatLngBounds();
resultsPanel = new google.maps.DirectionsRenderer({suppressMarkers:true});
resultsPanel.setMap(map);
$("#progressbar").progressbar(0);
var companyaddress = getCompanyAddress();
setCompanyMarker(companyaddress,companyname)
}
On resize I recalculate the height so that it fills the full page. If I don't do this then the map opens with 1px height, though I don't know why. Could that be the same issue?
function calculateHeight(){
var height = $('#maincontent').height();
$('#map-canvas').css("height",height);
}
$(window).resize(function () {
calculateHeight();
});
Since the map appears when the user resizes the window manually I thought programatically calling the resize event would have the same effect, so I added this:
$(window).trigger('resize');
But that did nothing.
I tried moving the api script to the map page but that caused a "You've loaded the same script multiple times" error if I load the page more than once, which then triggered other errors. However, with this setup I was able to load the map successfully using ajax after three page loads. In other words, after loading the container page once, I have to click on the menu item (that loads the map page) three times to get it to load properly. the first two times it still fails to load properly, but after that it loads properly every time, though with a load of JavaScript errors.
I also tried loading the api script asynchronously as per this suggestion.
I also tried adding "async defer" to the api script as per this suggestion.
Neither of these suggestions worked, and now I'm here.
What is causing the map to load with a grey background when the page is loaded via ajax, and what can I do about it?
1.Make sure map-canvas have width set in CSS.
2.When exactly did you try calling google.maps.event.trigger(map,'resize'); as geocodezip suggested? You need to call it after any map-canvas div's dimension change (calculateHeight) or any change to visibility of maps div. If the map-canvas div, or it's parent, or it's parent's parent (any predecessor) has display:none set at some point, the map view won't initialise properly and you will only see gray map. Also add the map resize code into some timeout to be sure, and then lower it if it works, e.g:
function calculateHeight(){
var height = $('#maincontent').height();
$('#map-canvas').css("height",height);
setTimeout(function(){ //also do this after any other visibility/dimension change
google.maps.event.trigger(map,'resize');
}, 500);
}
Try this, which worked for me
google.maps.event.addListener(map, 'idle', function()
{
google.maps.event.trigger(map, 'resize');
});
map.setZoom( map.getZoom() - 1 );
map.setZoom( map.getZoom() + 1 );
I have this code below:
layoutV.layout.open('east');
google.maps.event.addListenerOnce(map, 'idle', function() {
var center = map.getCenter();
google.maps.event.trigger(map, "resize");
map.setCenter(center);
});
layoutV will popout and the listener will start to resize my map and center the marker based on the new size of the window. Problem is, the map and marker only centers/resize once I drag the the mouse in the map. If I don't then nothing happens. Am I missing something or is it supposed to behave like this?
I even added the map.checkResize() after the .setCenter but nothing happnes.
Try This
function map_resize()
{
var center = map.getCenter();
google.maps.event.trigger(map, 'resize');
map.setCenter(center);
}
Was able to fix it by adding a window.setTimeout before the addlistener.
layoutV.layout.open('east');
window.setTimeout(function() {
map.setZoom(18);
}, 300);
google.maps.event.addListenerOnce(map, 'idle', function() {
var latLngAdjust = map.getCenter();
google.maps.event.trigger(map, "resize");
map.setCenter(latLngAdjust);
map.checkResize()
});
Now once I click a marker on the map, the window resizes and also the map and marker is at the center. ty...
So, the idle event only fires after 'panning or zooming.' Since you're triggering resize inside this event handler, it would only execute the code after an "idle" event (panning or zooming).
I'm not sure what the layoutV.layout.open bit is doing, but there is this: When you're trying to recenter a map you must get the current center before any resizing occurs. So, It seems that the open('east') is doing this, so before calling the open('east'), store the maps center in a var. Then, you can do your resize trigger and
map.setCenter(center);
with the center that was stored before the containing element changed size.
I have a <div> containing a leaflet map. Upon certain events the height of the <div> will be altered. I'd like for the map to resize to the new dimensions of its surrounding <div> so that the old center is centered in the resized smaller or larger map. I tried using the invalidateSize() function, but it doesn't seem to work at all. How can I resize and center the map after that map-container-resize event?
$mapContainer.on('map-container-resize', function () {
map.invalidateSize(); // doesn't seem to do anything
});
Edit to give more context:
The map container is styled initially as
#map-container {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
transition: height 0.5s ease-in-out;
}
After a user clicks a certain button, another panel shows at the bottom of the page and the map-container's height will be reduced to something less than 100% (say 80%).
Upon click on this button, the map-container-resize event is triggered so that I can make the map resize and center on its old (i.e. before the resizing happened) center. The map itself should then also be resized to 80% of its initial height.
The APi doc for invalidateSize seemed to be what I wanted:
"Checks if the map container size changed and updates the map if so
[...]"
But having a look with the output of the getSize function before and after the call to invalidateSize, nothing is different, the map remains at its old size.
The problem is that the resizing of the #map-container div is done via a css transition. The transition hasn't started yet, let alone ended, when the call to invalidateSize happens so the leaflet map cannot recognize any change of dimensions of its surrounding div.
Triggering the map-container-resize event with a delay solved the problem. This way :
setTimeout(function(){ map.invalidateSize()}, 400);
L.Map.invalidateSize() only informs leaflet map object that its container size has been changed, and therefore is should draw less or more map tiles. It does not actually change any dimensions, e.g. of its containing <div>, and does not move the map. You should do it yourself.
I came across this question today and wanted to provide an updated answer based on 2020 Browser API. This example uses the Browser's ResizeObserver to monitor the size of the div that Leaflet is mounted too. Assuming the following HTML Snippet:
<div id="map" />
With the following JavaScript:
const mapDiv = document.getElementById("map");
const map = L.map(mapDiv).setView([51.505, -0.09], 13);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map);
const resizeObserver = new ResizeObserver(() => {
map.invalidateSize();
});
resizeObserver.observe(mapDiv);
This should monitor the map div, and call the invalidateSize() method on the Leaflet map when the map div size changes. This approach allows you to handle the resizing "closer" to the map code, rather than trying to rely on window resize events or listening for changes triggered elsewhere in the application.
Obviously the CSS for the map div itself will need to ensure that it resizes in whatever way you want it to. This code snippet will ensure the Leaflet is appropriately updated when that happens.
You can use below code after resize that
map.invalidateSize()
https://github.com/Leaflet/Leaflet/issues/690
the accepted answer is a bit hacky in that it relies on the sleep being longer than the transition.
I have found this to work well:
$("body").on($.support.transition.end, '#main-navbar .nav-collapse', function(event){
console.log("end of the animation");
});
Just call resize window event rather than timing the map to load.
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map);
window.dispatchEvent(new Event('resize'));
// Triggers a window resize
// Thus your map automatically triggers invalidateSize().
Ran into this problem running VueJS, Leaflet 1.2.0. The resizing didn't appear complete as others mentioned above. My solution within VueJS was to call the nextTick function:
var vm = this
var container = vm.$refs.container
vm.mapStyle.width = `${vm.getElementContentWidth(container)}px`
vm.mapStyle.height = `${vm.getElementContentHeight(container)}px`
vm.$nextTick(() => {
if (vm.map) vm.map.invalidateSize()
if (vm.layerBase) vm.layerBase.redraw()
})
I believe pure javascript would be