Google Maps JS v3: Map display: none; after map initialization causing corrupted map
This certainly touches on previous questions regarding map display during initialization. Yet the issue here is with map display being set to none after map should have already initialized. The last line of my widow.onload sets the map to display: none; The map initialization should have already completed by that time, but the fact remains, the final call is causing the problem.
window.onload(); function...
window.onload = function(){
changeTheme(me); // do it now so current_theme is avaible to switchTabs();
switchTabs("tab3"); // sets map div visible
initMaps(); // map initialization. code included.
loadFavoritePlaces(); // asynch $getJSON call, adds markers. No matter the condition of map, markers appear in their proper locations.
closePopup("images");
closePopup("location"); // sets maps.mini_map display: none; Problems if we loadUserTable() later. Otherwise OK. Odd!
closePopup("tweet");
centerDiv();
document.title = '@'+me.screen_name+' - PithyTwits.com';
users[me.id_str] = me;
getPage(); // asynch $.getJSON loads tweets. Not an issue.
// Append a scroll event handler to tweet_div
$("#tweet_div").scroll(function() {
var pos = $(this)[0].scrollHeight - $(this).scrollTop();
if(pos != prev_scroll){ // hack to prevent scroll 开发者_如何学Cfunction from firing twice
prev_scroll = pos;
if (pos == $(this).outerHeight()) {
$("#throbber").fadeIn();
getPage();
}
}
});
loadUserTable(me.id_str);
/* loadUserTable(); calls switchTabs("tab1"); which sets map div display: none;
if I comment this out the map initialization completes properly, but my 'tab1'
doesn't get populated properly. And page doesn't start on 'tab1', which is required. */
// end window.onload()
}
initMaps(); function...
function initMaps() {
// markers list
maps.markers = new Object;
// visibility status'
maps.markerStatus = new Object;
maps.markerStatus['query'] = true;
maps.markerStatus['tweet'] = true;
maps.markerStatus['favorite'] = true;
// define marker images
maps.reticleImage = new google.maps.MarkerImage('images/reticle.png',
new google.maps.Size(63, 63),
new google.maps.Point(0,0),
...
Declarations removed to streamline post.
...
new google.maps.Point(0,0),
new google.maps.Point(1, 13));
maps.markerShape = {
type: "poly",
coords: [9,22,16,11,16,5,11,1,6,1,2,5,2,11,9,22]
}
// setup map options
var latlng = new google.maps.LatLng(39.520427, -94.770621);
var latlng2 = new google.maps.LatLng(46.1912, -122.1944);
var myOptions = {
zoom: 3,
center: latlng,
mapTypeId: google.maps.MapTypeId.HYBRID
};
var myOptions2 = {
zoom: 13,
center: latlng2,
disableDefaultUI: true,
draggable: false,
keyboardShortcuts: false,
mapTypeControl: false,
scrollwheel: false,
mapTypeId: google.maps.MapTypeId.HYBRID
};
// initialize maps
maps.main_map = new google.maps.Map(document.getElementById("map_div"), myOptions);
maps.mini_map = new google.maps.Map(document.getElementById("mini_map"), myOptions2);
// default map center markers
maps.mini_map_marker = new google.maps.Marker({
position: latlng2,
map: maps.mini_map,
icon: maps.favoriteMarker,
shadow: maps.markerShadow,
});
maps.reticleMarker = new google.maps.Marker({
position: latlng,
map: maps.main_map,
shape: reticleShape,
icon: maps.reticleImage,
});
// event handlers
google.maps.event.addListener(maps.main_map, 'zoom_changed', mapZoomed);
google.maps.event.addListener(maps.main_map, 'bounds_changed',
function(){maps.reticleMarker.setPosition(maps.main_map.getCenter());});
//idle event listener provided by @Guan in the marked answer.
google.maps.event.addListenerOnce(maps.main_map, 'idle', function() {
var div = document.getElementById("tab3_content");
div.style.display = "none";
div.style.position = "relative";
div.style.left = "0px";
});
// initialize controls
var controls = document.getElementById("visibility_controls");
maps.main_map.controls[google.maps.ControlPosition.TOP_CENTER].push(controls);
controls.style.display = "inline";
var controls = document.getElementById("control_controls");
maps.main_map.controls[google.maps.ControlPosition.RIGHT_CENTER].push(controls);
controls.style.display = "inline";
var controls = document.getElementById("query_controls");
maps.main_map.controls[google.maps.ControlPosition.BOTTOM_CENTER].push(controls);
controls.style.display = "inline";
}
If I call loadUserTable(); at the end of window.onload(); I get this... (munged)
If I don't call loadUserTable(); at the end of window.onload(); I get this... (correct)
Since the problem stems from the maps display being set to none after the maps should have initialized, it would lead one to believe that the map initialization is actually happening non-syncronously. So how do I know when it is finished, and it is safe to hide the maps div? And also there is the question of why the mini_map seems to be dependent on visibility of the main_map, rather than its own visibility? I get the same results in both Chrome and Firefox, on Linux.
Any help is help :)
Skip
UPDATE: I changed the final call to setTimeout("loadUserTable();", 1000); and 1 second is enough of a pause to let things work, but isn't what I want! Since @Jobsz verifies this is known issue, I'm going to resort to off screen initialization, and move the map into position either when needed for display, or hide it and put it in position after a short timeout.
SOLUTION: Provided by @Guan (Checked answer)
I did not want the map visible during initialization. But wanted it initialized and ready when the user chose that tab.
The map div is initially set thus...
id="tab3_content" style="display: block;position: absolute; left: -1000px;"
That makes it visible, but offscreen to the left.
And then set a listener for the idle event in the map initialization...
google.maps.event.addListenerOnce(maps.main_map, 'idle', function() {
var div = document.getElementById("tab3_content");
div.style.display = "none";
div.style.position = "relative";
div.style.left = "0px";
});
That event fires once when the map is idle(ready). It hides the div and moves it into position on screen.
The loadUserTable() function is called in the normal program flow, and life is good. :)
Could you try calling
//map hold's a reference to your current map
google.maps.event.trigger(map, 'resize');
After the map/div containing it becomes visible?
google.maps.event.addListenerOnce(map, 'idle', function() {
$('#addstop').css({
display: 'none',
left: '0',
top: '0'
});
});
This event happens only once after the map is fully loaded and 'idle'
Yup -- I had this same problem.
What I did was trigger the initialization after the event button that displays the hidden map is clicked.
So I have a hidden div, when it's clicked to shown, i display it and then initalize it. Is this doable for what you're trying to achieve? I'm assuming you want performance in that you'd prefer the click to instantly show a populated map -- however it isn't too slow to populate the small area you're tying to if you do it on the click event.
Just this may help you.
I just have an application that uses tabs mixed with gmap divs.
I was fix same problems. Console just show corruption image message. Your ideas help a lot!
I just use this
$("#tab-3").click(function(){
$(".tab-3").removeClass("ui-screen-hidden");
$(".tab-1").addClass("ui-screen-hidden");
$(".tab-2").addClass("ui-screen-hidden");
initializedonationlocation();
})
function initializedonationlocationdr() {
var directionsDisplay = new google.maps.DirectionsRenderer();
geocoder2 = new google.maps.Geocoder();
infowindow2 = new google.maps.InfoWindow();
var myOptions = {
zoom: 10,
center: new google.maps.LatLng(38.7,-121.59),
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map2 = new google.maps.Map(document.getElementById('my_map_donation_donationreceipt'),
myOptions);
google.maps.event.addListener(map2, 'click', function(e) {
geocoder.geocode(
{'latLng': e.latLng},
function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
if (results[0]) {
if (marker2) {
marker2.setPosition(e.latLng);
} else {
marker2 = new google.maps.Marker({
position: e.latLng,
map: map2});
}
infowindow2.setContent(results[0].formatted_address);
var postCode = extractFromAdress(results[0].address_components, "postal_code");
var street = extractFromAdress(results[0].address_components, "route");
var town = extractFromAdress(results[0].address_components, "locality");
var country = extractFromAdress(results[0].address_components, "country");
var state = extractFromAdress(results[0].address_components, "administrative_area_level_1");
$("#city_donationdr").val(town);
$("#state_donationdr").val(state);
$("#zip_donationdr").val(postCode);
$("#address_donationdr").val(street);
infowindow2.open(map2, marker2);
// Changing window
var prevSelection3 = $("#tabmap").val();
var newSelection3 = $("#navbar2 ul li").children("a").attr("data-tab-class");
$("."+prevSelection3).addClass("ui-screen-hidden");
$("."+newSelection3).removeClass("ui-screen-hidden");
prevSelection3 = newSelection3;
$("#tabmap").val(prevSelection3);
document.getElementById('geocoding').innerHTML = "";
$("#coords_donationdr").val(e.latLng);
$("#address_donationdr").focus();
GetCurbSideCoordsDR(directionsDisplay,map2);
} else {
document.getElementById('geocoding').innerHTML =
'No results found';
}
} else {
document.getElementById('geocoding').innerHTML =
'Geocoder failed due to: ' + status;
}
});
});
}
I only call initialization only when tab that contain gmap is showed. NOT before. Many forums show gmap initialization at pages loading. In conbination with tabs, just only call initialization after tab appears.
精彩评论