April 30, 2013 Update: Post and template updated to include a more modern application cache loading script as well as utilizing my GeolocationMarker code and the latest Maps API v3 options.
Developing a map for mobile devices presents unique challenges. Not only must your user interface work on a small screen and be optimized for touch, but your map needs to load fast.
Note: This article is about maps for iPhone and Android devices. Many of the techniques here are optimized for HTML5 browsers and will not work in Internet Explorer or older browsers. While techniques exist to support similar functionality on other browsers, they are beyond the scope of this article.
Must go faster
Speed to the user can be a tricky thing to measure. Do you measure until when your map, custom layers, markers and location are fully loaded? Or do you measure until the user can first interact with the map? Whatever the choice, it is important to provide feedback to the user so that they can at least see progress.
Delay loading the Maps API
Script tags block page rendering until they are completely downloaded and processed. This can be a significant wait on slower devices when loading the Maps API during which time the user won’t see any progress. To allow your page to load first, dynamically add the Maps API on the DOMContentLoaded event. When you use this technique, you’ll need to add a callback parameter to the script source to know when the API has finished loading.
Delay loading map customization scripts until the Maps API loads
HTML5 offline storage
This is basically caching on steroids. This has been covered elsewhere, but it should be mentioned that this alone makes a HUGE difference for return visits. There are a couple of things to keep in mind when developing a cache-manifest file:
- Every URL used in the site must be specified in either the CACHE or the NETWORK sections. The CACHE section takes specific urls while the NETWORK section takes URL prefixes.
FireFox will cache this seemingly permanently. To clear it, remove your site from the Offline Storage section of the options (under Advanced – Networking). Chrome treats this similarly (only available in the 5.0 and later versions).Application cache usage is temperamental. See my post on the challenges of using the application cache with an external API.
Sample CACHE-MANIFEST file:
CACHE MANIFEST /examples/template.htm /examples/template.css /examples/template.js http://missouristate.info/images/2010/loading.gif http://missouristate.info/images/2010/map/gpsloc.png NETWORK: http://maps.gstatic.com/ http://maps.google.com/ http://maps.googleapis.com/ http://mt0.googleapis.com/ http://mt1.googleapis.com/ http://mt2.googleapis.com/ http://mt3.googleapis.com/ http://khm0.googleapis.com/ http://khm1.googleapis.com/ http://cbk0.googleapis.com/ http://cbk1.googleapis.com/ http://www.google-analytics.com/ http://gg.google.com/ http://csi.gstatic.com/
Note: The URLs listed above are subject to change without notice. When using the Google Maps API via SSL there are slightly different versions of the addresses.
Follow industry best practices
Use the Google Page Speed tool to help optimize your site. While the suggestions are relevant to any site, they make a much bigger impact on mobile devices due to the high latency connections and device processor/memory constraints.
Not only must your map function on a small screen, but there is a wide variety of screen sizes among devices.
Dynamic map height
<div id="map_canvas" style="position:absolute;top:30px;bottom:50px;left:0;right:0;"></div>
Show a progress indicator
Lack of feedback will frustrate your users. It’s rather simple to display a progress indicator to let your users know that the map is actually loading. Adding an overlay div to indicate loading is an easy way to show this. You can disable the loading div in the tilesloaded event.
Use the special link and meta tags
Both Android phones and the iPhone support a number of link and meta tags for sites which are designed to function as an application. Here’s a list of the one’s most applicable to a map:
|link||apple-touch-icon||Url of PNG Icon||iPhone and Android||Android doesn’t add gloss to icons|
|link||apple-touch-icon-precomposed||Url of PNG Icon||iPhone and Android||The iPhone won’t add gloss to this icon|
|link||app-touch-startup-image||Image to display while loading||iPhone||Only shows when the site has been saved then launched from the home screen.|
|meta||apple-mobile-web-app-capable||“yes”||iPhone||Indicates that the site is designed to function as a standalone application (launched from the homescreen) without browser chrome.|
|meta||viewport||initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0||iPhone and Android||Indicates that the browser should display the site without scaling and disable zooming the entire page since the map handles zooming.|
Use high resolution images
Newer mobile devices (and now even laptops and desktops) come with high-density displays. To make full use of these, your map needs to use high resolution graphics. I have found that using CSS selectors based of the device-pixel density to be unreliable as there doesn’t seem to be a common meta viewport tag that will correctly report the density across all browsers. Instead, I’ve found it is just easier to make all images twice the size and scale them to 50% via CSS. Map markers and overlays can use a similar technique using the scaledSize property of the Icon object. Unfortunately at this point in time there is not a way to use high resolution icons in KML or Fusion Table Layers.