Phonegap app with jQuery Mobile 1.4 and Google Maps JavaScript API v3.
The map takes a couple seconds to load on a mobile device, sometimes longer. I\'m trying to \"
You can achieve this by loading map canvas once first page is fully loaded and shown. However, map canvas should be placed in a div that isn't visible in current viewport. Using display: none;
on map canvas will break the structure and becomes unresponsive when you move it from div to another.
Another important note, height of content div are always 0 before and after creating a page. Hence, content div's height should be predefined in order to accommodate map canvas after it is loaded in background.
First step:
Create a map placeholder outside any page div, and make sure it isn't within viewport view by changing it's position
CSS property. Inside map placeholder, add map canvas div. Moreover, remove content div padding
to fill the whole available area.
HTML
<div id="mapPH">
<div id="map-canvas"></div>
</div>
CSS
#mapPH {
position: absolute;
top:-999;
z-index: -9999;
}
.ui-content {
padding: 0;
}
Second step:
On any jQM's page events, load map into map canvas ONLY one time .one()
. Once it fully loaded, move to its' new parent. You can either move it automatically once loaded by listening to tilesloaded
event, or move it once to change to map page.
var mapOptions = {
center: new google.maps.LatLng(36.4875, -4.9525),
zoom: 16,
mapTypeId: google.maps.MapTypeId.HYBRID,
mapTypeControl: false,
streetViewControl: false,
zoomControlOptions: {
position: google.maps.ControlPosition.RIGHT_BOTTOM
}
};
var map = new google.maps.Map($(canvas)[0],
mapOptions);
var marker = new google.maps.Marker({
position: new google.maps.LatLng(36.4875, -4.9525),
map: map,
title: 'Hello World!'
});
/* move map once fully loaded
by listening to "tilesloaded".
Remove "placeholder" after moving the map */
google.maps.event.addListener(map, 'tilesloaded', function () {
$("#map .ui-content").append($("#mapPH #map-canvas"));
$("#mapPH").remove();
});
/* or choose any other method to move it */
$(".selector").on("click", function () {
$("#map .ui-content").append($("#mapPH #map-canvas"));
$("#mapPH").remove();
});
Third step:
Here comes the tricky part, map canvas's dimensions (width & height). As I've mentioned before, content div's height should either predefined manually or dynamically using the below function.
function canvasHeight(canvas) { /* canvas = map's canvas ID */
var canvasPage = $(canvas).closest("[data-role=page]").length !== 0 ? $(canvas).closest("[data-role=page]") : $(".ui-page").first(),
screen = $.mobile.getScreenHeight(),
header = $(".ui-header", canvasPage).hasClass("ui-header-fixed") ? $(".ui-header", canvasPage).outerHeight() - 1 : $(".ui-header", canvasPage).outerHeight(),
footer = $(".ui-footer", canvasPage).hasClass("ui-footer-fixed") ? $(".ui-footer", canvasPage).outerHeight() - 1 : $(".ui-footer", canvasPage).outerHeight(),
newHeight = screen - header - footer;
$(canvas).height(newHeight);
$(canvas).width($(window).width());
}
That function should be called once map canvas is loaded as well as when moving it. However, to get actual dimensions, a setTimeout()
is required here, since the page you're moving to is still not created. When a page isn't created, you won't get actual/true height of elements within that page.
Update: map canvas's dimensions should be updated on two events, throttledresize
and orientationchange
.
$(window).on("throttledresize orientationchange", function () {
canvasHeight("#map-canvas");
});
Here is the complete code for more clarification.
/* map canvas dimensions */
function canvasHeight(canvas) {
var canvasPage = $(canvas).closest("[data-role=page]").length !== 0 ? $(canvas).closest("[data-role=page]") : $(".ui-page").first(),
screen = $.mobile.getScreenHeight(),
header = $(".ui-header", canvasPage).hasClass("ui-header-fixed") ? $(".ui-header", canvasPage).outerHeight() - 1 : $(".ui-header", canvasPage).outerHeight(),
footer = $(".ui-footer", canvasPage).hasClass("ui-footer-fixed") ? $(".ui-footer", canvasPage).outerHeight() - 1 : $(".ui-footer", canvasPage).outerHeight(),
newHeight = screen - header - footer;
$(canvas).height(newHeight);
$(canvas).width($(window).width());
}
/* map canvas loading */
function loadMap(canvas) {
var mapOptions = {
center: new google.maps.LatLng(36.4875, -4.9525),
zoom: 16,
mapTypeId: google.maps.MapTypeId.HYBRID,
mapTypeControl: false,
streetViewControl: false,
zoomControlOptions: {
position: google.maps.ControlPosition.RIGHT_BOTTOM
}
};
var map = new google.maps.Map($(canvas)[0],
mapOptions);
var marker = new google.maps.Marker({
position: new google.maps.LatLng(36.4875, -4.9525),
map: map,
title: 'Hello World!'
});
/* option 1: moving map once loaded */
google.maps.event.addListener(map, 'tilesloaded', function () {
$("#map .ui-content").append($("#mapPH #map-canvas"));
$("#mapPH").remove();
});
}
/* load map in background
once first page is shown
and update its' dimensions */
$(document).one("pagecontainershow", function () {
canvasHeight("#map-canvas");
loadMap("#map-canvas");
/* option 2: move map on "click"
and update its' dimensions */
$(".showMap").one("click", function () {
$("#map .ui-content").append($("#mapPH #map-canvas"));
setTimeout(function () {
canvasHeight("#map-canvas");
}, 500);
$("#mapPH").remove();
});
});
/* update map canvas dimensions
when window is resized and changing orientation */
$(window).on("throttledresize orientationchange", function () {
canvasHeight("#map-canvas");
});
Demo