Normally Microsoft's Map application on a Lumia device is perfect for travelling, but it turns out there isn't an offline map available for Japan. After trying several alternatives, I figured that I could maybe create something better as a feature to my side project. I needed this to be compatible with the Edge browser, and for it to function effectively without a WiFi connection. Is this achievable using just HTML5, CSS and JavaScript? Yes, it is.

Creating the Offline Map Files

The first thing we need is data, in the form of map tiles, and the easiest way of getting this is by generating them using the Mobile Atlas Creator. This is straightforward to use - simply select the region to map and the zoom levels the application would display (e.g. all of them), and create the atlas .zip archive. The archive contains sets of numbered directories and files - I'll explain why they're structured that way and how they're read by the application. For the data source, 'OpenStreetMap Public Transport' gave the clearest tile images.

Leaflet.js API

There are multiple JavaScript APIs for rendering maps in the browser and showing the current GPS position. I went with Leaflet.js, as it's lightweight, functional and reasonably well-documented.
This is roughly how Leaflet.js does the rendering: Leaflet.js will select the images to display according to the co-ordinates set in the code. The API will translate the co-ordinates into two five-digit numbers to select the file paths of the tiles to display. There is a third variable, which is the zoom level and layer - this determines the root directory that Leaflet.js will fetch the tiles from.



The three aforementioned factors are variables, z, x and y in the code. These correspond to the zoom level, latitude and longitude. All three are initially determined by the setview() parameters - the default zoom level and initial map frame displayed, but they're changed by the JavaScript controls as the user scrolls and zooms in and out.

Geolocation

Leaflet.js includes a feature that makes use of the browser's geolocation API. We include a button with this event trigger: onClick="javascript:getLocationLeaflet();" Which calls this function: function getLocationLeaflet()
{
map.on('locationfound', onLocationFound);
map.on('locationerror', onLocationError);
map.locate({setView: true, maxZoom: 16});
}
Which, in turn, calls this function if the current location can be read from the device: function onLocationFound(e)
{
var radius = e.accuracy / 2;
var location = e.latlng
L.marker(location).addTo(map)
L.circle(location, radius).addTo(map);
}



Of course, there's no map in the screenshot here, as there aren't any tiles for that location.

Location Markers

Another feature essential to my application is the ability to mark important locations on the map and display information about them. In this example, the placemark locations and popup messages are hard-coded into the JavaScript, though it should be possible to load that information from a GeoJSON file without having to use something like Node.js (I'm still working on this).

With the markers, the init() function should look something like this: function init() {
map = new L.Map('map');
L.tileLayer('maps/kyoto-atlas/kyoto/{z}/{x}/{y}.png', { maxZoom: 15 })
.addTo(map);
map.setView(new L.LatLng(34.98852, 135.764982), 16);

L.marker([34.967169, 135.772437]).addTo(map)
.bindPopup('Fushimi Inari Shrine')
.closePopup();

L.marker([35.016917, 135.782388]).addTo(map)
.bindPopup('Heian Shrine')
.closePopup();

L.marker([35.008699, 135.767091]).addTo(map)
.bindPopup('Market Square')
.closePopup();

L.marker([34.985985, 135.741648]).addTo(map)
.bindPopup('Kyoto Railway Museum')
.closePopup();
}
Don't forget there is always the CSS file included with Leaflet.js.



It shouldn't matter whether the map files are replaced with something better from the Mobile Atlas Creator, as the co-ordinates within the JavaScript will always be mapped to the correct places.

To minimise the download size, I've published this example on GitHub with map tiles for only one zoom level, but it's easy to recreate what I've done in the Mobile Atlas Creator.

References

AGAFONKIN, V. 2017. Leaflet: an open-source JavaScript library for mobile-friendly interactive maps. [WWW]. http://leafletjs.com/. (17th March 2018).

r_x. 2018. Mobile Atlas Creator. SourceForge. [WWW]. https://sourceforge.net/projects/mobac/. (18th March 2018).