Pretty near the close of play yesterday I discovered that the GIS solution my organisation uses won’t integrate with the Windows 8 Store app that I am developing (WinJS IFRAME Permission Denied). My boss and I agreed that looking at a mapping API such as the one that BING provides was worth doing in the context of the project because it will come up sooner rather than later and I would much rather be prepared.
So I spent quite a frustrating few hours this morning trying to get the API to integrate with a Windows Store App. Actually getting a map to render was quite easy – this post on the BING maps blog told me everything I needed to know. But moving on from that and getting basic functionality such as zooming the map in / out on a button click was irritating.
I read somewhere that the API is the same as the Javascript AJAX API described on this site but the suggestion of map.ZoomIn() to get the map to zoom, for example, didn’t work.
There are a few code samples scattered across the web for C# / XAML, a few for Javascript but there doesn’t seem to be a single central source for developing maps in Javascript / HTML 5 for Windows Store. Bit disappointed at the lack of support at the moment, and surprised too because a lot of what mobile devices can offer is location – based data and services.
Anyway, here’s what I have managed to figure out so far:
1. The samples will tell you to create a div to act as a container for the map on the screen. By default the map takes over the entire screen, so if you want to make it a certain size the css is:
<div id="myMap" style="position: relative; width: 100%; height: 100%;"></div>
Here’s the HTML for a Page that I have added to the solution called map.html. I’ve created a grid structure with the map on the left of the page and a couple of spans and a couple of buttons on the left for zoom in / out and displaying lat / long of current position.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>map</title>
<!-- WinJS references -->
<link href="//Microsoft.WinJS.1.0/css/ui-dark.css" rel="stylesheet" />
<script src="//Microsoft.WinJS.1.0/js/base.js"></script>
<script src="//Microsoft.WinJS.1.0/js/ui.js"></script>
<link href="map.css" rel="stylesheet" />
<script src="map.js"></script>
<!-- load jquery -->
<script src="/js/libraries/jquery-1.8.2.min.js"></script>
<script type="text/javascript" src="ms-appx:///Bing.Maps.JavaScript//js/veapicore.js"></script>
<script type="text/javascript" src="ms-appx:///Bing.Maps.JavaScript//js/veapiModules.js"></script>
</head>
<body>
<div class="map fragment">
<header aria-label="Header content" role="banner">
<button class="win-backbutton" aria-label="Back" disabled type="button"></button>
<h1 class="titlearea win-type-ellipsis">
<span class="pagetitle">Title</span>
</h1>
</header>
<section aria-label="Main content" role="main">
<div id="content" style="display: -ms-grid; -ms-grid-rows: 1fr 1fr; -ms-grid-columns: 60% 60%; height: 100%; overflow: scroll;">
<div id="leftContainer" style="-ms-grid-column: 1; -ms-grid-row: 1; -ms-grid-row-span: 2;">
<div id="myMap" style="position: relative; width: 100%; height: 100%; "></div>
</div>
<div id="rightContainer" style="-ms-grid-column: 2; -ms-grid-row: 1;">
<span id="lat">LAT</span>
<br />
<span id="long">LONG</span>
<br />
<button id="zoomin">Zoom In</button>
<br />
<button id="zoomout">Zoom Out</button>
</div>
</div>
</section>
</div>
</body>
</html>
Here’s the javascript ‘code behind’. It loads the map (you will need to generate your own API key, see the BING blog link above) and set your own starting lat / long. There are handlers for the zoom in / out buttons and there’s also code that I have taken straight from the Microsoft site to use Geolocation – don’t forget to enable it in your appmanifest. You’ll also need to run the solution through the simulator on VS2012 and click the ‘Get Location’ button in the tool bar on the right hand side of the simulator. Notice how the zoom in / out use map.setView to set the zoom level.
// For an introduction to the Page Control template, see the following documentation:
// http://go.microsoft.com/fwlink/?LinkId=232511
(function () {
"use strict";
var map = null;
var loc = null;
function initMap() {
try {
var mapOptions = {
credentials: "api-key-here",
center: new Microsoft.Maps.Location(lat, long),
mapTypeId: Microsoft.Maps.MapTypeId.road,
zoom: 15
}
var mapDiv = document.querySelector('#myMap');
map = new Microsoft.Maps.Map(mapDiv, mapOptions);
}
catch (e) {
var md = new Windows.UI.Popups.MessageDialog(e.message);
md.showAsync();
}
}
function getLoc() {
if (loc == null) {
loc = new Windows.Devices.Geolocation.Geolocator();
}
if (loc != null) {
loc.getGeopositionAsync().then(getPositionHandler, errorHandler);
}
}
function getPositionHandler(pos) {
document.getElementById("lat").innerHTML = pos.coordinate.latitude;
document.getElementById("long").innerHTML = pos.coordinate.longitude;
}
function errorHandler(e) {
//var md = new Windows.UI.Popups.MessageDialog(e.message);
var md = new Windows.UI.Popups.MessageDialog(getStatusString(loc.locStatus));
md.showAsync();
}
function getStatusString(locStatus) {
switch (locStatus) {
case Windows.Devices.Geolocation.PositionStatus.ready:
return "Location is available";
break;
}
}
WinJS.UI.Pages.define("/pages/map/map.html", {
// This function is called whenever a user navigates to this page. It
// populates the page elements with the app's data.
ready: function (element, options) {
Microsoft.Maps.loadModule('Microsoft.Maps.Map', { callback: initMap });
var hello = document.getElementById("zoomin");
hello.addEventListener("click", this.zIn, false);
var goodbye = document.getElementById("zoomout");
goodbye.addEventListener("click", this.zOut, false);
},
zIn: function () {
var zoom = map.getZoom();
zoom = zoom + 1;
map.setView({ zoom: zoom });
getLoc();
},
zOut: function () {
var zoom = map.getZoom();
zoom = zoom - 1;
map.setView({ zoom: zoom });
},
unload: function () {
// TODO: Respond to navigations away from this page.
},
updateLayout: function (element, viewState, lastViewState) {
/// <param name="element" domElement="true" />
// TODO: Respond to changes in viewState.
}
});
})();
I hope these samples help anyone who wants to integrate a map into a page – all the code samples I have seen so far presume that the map is going on default.html which won’t be for everyone, and the javascript on the page is subtly different.
Tags: AJAX, BING API, Maps, Windows 8