Integrating HERE Maps into your Tizen wearable app (Part 1)

Posted on Posted in Development, Wearables

HERE_Maps_example

Overview

This is Part 1 of a tutorial that details how HERE Maps can be implemented in your Tizen wearable application.

See HERE Maps Javascript API 3.0 for reference as well as additional examples in the API explorer.

Load the Maps API code libraries

In order to use the HERE Maps API for Javascript, we must first load the required code libraries or modules.  The implementation of our application requires three modules: core, service, and places.

The URL in the “src” attribute contains a version number that reflects the latest major release of the API.  Note that this version number changes with each new release, which may break backwards-compatibility.  See here for an explanation of version numbers.

In our app, the module.loadHereScript() function loads the modules:

module.loadHereScript = function() {
	
	if (!isInstanceInitialized){
		if (isScriptLoadRequested) {
			return;
		}
		isScriptLoadRequested = true;
		if (coreJs != null) {
			coreJs.parentNode.removeChild(coreJs);
			isCoreJsLoaded = false;
		}

		if (serviceJs != null) {
			serviceJs.parentNode.removeChild(serviceJs);
			isServiceJsLoaded = false;
		}
		if (placeJs != null) {
			placeJs.parentNode.removeChild(placeJs);
			isPlaceJsLoaded = false;
		}
		if (timeoutId > -1) {
			clearTimeout(timeoutId);
			timeoutId = -1;
		}
		timeoutId = setTimeout(function(){
			uiHelper.openPopup("Please check your internet connection and try again.",
				function(){
					isScriptLoadRequested = false;
					clearTimeout(timeoutId);
					timeoutId = -1;
					uiHelper.closePopup(true);
				}
			);
		}, 30000);	
		
		coreJs = document.createElement('script');
		coreJs.setAttribute("id","coreJs");
		coreJs.setAttribute("type","text/javascript");
		coreJs.setAttribute("src","http://js.api.here.com/v3/3.0/mapsjs-core.js");
		coreJs.async = false;
		coreJs.onload = function(){
			isCoreJsLoaded = true;
			serviceJs = document.createElement('script');
			serviceJs.setAttribute("id","serviceJs");
			serviceJs.setAttribute("type","text/javascript");
			serviceJs.setAttribute("src","http://js.api.here.com/v3/3.0/mapsjs-service.js");
			serviceJs.async = false;
			serviceJs.onload = function(){
				isServiceJsLoaded = true;
				placeJs = document.createElement('script');
				placeJs.setAttribute("id", "placeJs");
				placeJs.setAttribute("type", "text/javascript");
				placeJs.setAttribute("src", "http://js.api.here.com/v3/3.0/mapsjs-places.js");
				placeJs.onload = function(){
					isPlaceJsLoaded = true;
					isScriptLoadRequested = false;
					initInstance();
					if (timeoutId > -1) {
						clearTimeout(timeoutId);
						timeoutId = -1;
					}
				};
				document.getElementsByTagName("head")[0].appendChild(placeJs);
			};
			document.getElementsByTagName("head")[0].appendChild(serviceJs);
		};
		document.getElementsByTagName("head")[0].appendChild(coreJs);		    
	}
};
Initialize communication with HERE back-end services

Our app needs to communicate with the back-end services which process requests for map images and deliver them to our application to display.

To do this, initialize a Platform object with the app_id and app_code received on registration.  Obtain authentication and authorization credentials per application here.

The Platform object allows the use of the Customer Integration Testing instance of the HERE Platform and/or HTTPS when communicating with the back end.  These are not used in our app.

In our app, the Platform object is initialized in the initInstance() function:

function initInstance() {
	// Code not shown
	platform = new H.service.Platform({
		  'app_id': 'RMIdCzk8xkhnPkgXFY11',
		  'app_code': '4h_rrGVXZXoPeuHjAb9G4A',
		  useCIT: false,
		  useHTTPS: false
	});
	// Code not shown
};
Initialize a map object, displaying the map

To set up a Map object, specify the map type, zoom level, and any other desired parameters.

platform.createDefaultLayers() returns an object that holds the default map types and layers.

In our app, it is called in the initInstance() function:

function initInstance() {
	// Code not shown
	maptypes = platform.createDefaultLayers();
	// Code not shown
};

 
The default map types and layers are then used to initialize a Map instance, where the normal style of map is used by passing maptypes.normal.map as a parameter.  See the instantiation in module.initMap():

module.initMap = function(container) {
	// Code not shown
	map = new H.Map(mapView, maptypes.normal.map, 
		{ 
			zoom: 5,
			pixelRatio: 1
		}
	);	
	// Code not shown
};
Adding map objects

The API distinguishes between three different types of map objects: markers, spatials, and groups.  Our app utilizes all three.

Markers are objects that indicate locations on the map (point of interest).  Each marker is defined by a geographical point (latitude and longitude) to which it is anchored, and it includes an icon.  Panning the map changes the position of the marker on the screen, but the size of the marker icon remains constant when you change the map zoom level (if you zoom in or out).

Spatials are objects that can be used to mark areas on the map.  They can be circles, rectangles, polylines and polygons and are defined by a set of geographical points.  The set of points are translated and scaled as the map is panned and zoomed so that the shape that is displayed faithfully reflects its geographic location.  A spatial object includes styling information, which determines how to trace its outlines and how to fill it (if it is a closed shape).

Groups are logical containers which can hold a collection of child objects (markers, spatials, and even sub-groups).  Groups make it easy to manipulate multiple map objects all at once.  In addition, a group allows you to calculate a bounding box enclosing all the objects it contains and to listen for events dispatched by the group’s child objects.

To make an object appear on the map, it must be added to the map’s root group through a call to the map object’s method addObject().

Marker

There are two Marker objects in our app, a myLocationMarker which represents the user’s current location and a destinationMarker which represents their destination. destinationMarker then gets an icon if a conditional is met while myLocationMarker uses the default icon since one is not set for it.  They are both initialized in the module.initMap() function:

module.initMap = function(container) {
	// Code not shown
	myLocationMarker = new H.map.Marker({lat:myLocation.lat, lng:myLocation.lng});
	destinationMarker = new H.map.Marker({lat:destination.lat, lng:destination.lng});
	if (isLastMile) {
		
	} else {
		destinationMarker.setIcon(carIcon);
	}
	// Code not shown
};

 
The icon carIcon used for destinationMarker is defined in the initInstance() function:

function initInstance() {
	// Code not shown
	carIcon = new H.map.Icon("css/images/CarPin@2x.png", {size:{w:48, h:60}});
	// Code not shown
};
Groups

myLocationMarker and destionationMarker are then added to a group where they can be manipulated as a pair (both added to map at same time):

module.initMap = function(container) {
	// Code not shown
	group = new H.map.Group();
	group.addObjects([myLocationMarker, destinationMarker]);
	map.addObject(group);
	map.setViewBounds(group.getBounds());
	// Code not shown
};
Spatials (polyline)

Our app uses a polyline to display the path from myLocationMarker to destinationMarker.  A polyline is a line on the map defined in terms of a set of points (represented in the API as a geo.Strip), and a style, which defines the way the Maps API traces the line on the map.

Before creating a polyline, a Strip must be created, which represents an ordered set of points.  This Strip instance is a point source for the polyline and is initialized from the route.shape.  Then the polyline is initialized with the strip.  Strip and polyline initialization and usage are executed in the sub-function routeService.calculateRoute() of the module.initMap() function:

module.initMap = function(container) {
	// Code not shown
	strip = new H.geo.Strip();
	routeShape = route.shape;

	routeShape.forEach(function(point) {
		parts = point.split(',');
		strip.pushLatLngAlt(parts[0], parts[1]);
	});

	polyline = new H.map.Polyline(strip, {
		style: {
			lineWidth: 10,
			strokeColor: 'rgba(0, 128, 255, 0.7)'
		},
		arrows: { fillColor: 'white', frequency: 2, width: 0.8, length: 0.7 }
	});

	map.addEventListener("mapviewchangeend", mapviewchangeendListener);
	map.addObject(polyline);
	map.setViewBounds(polyline.getBounds(), true);
	map.setZoom(map.getZoom() - 1);		    		  
	// Code not shown
};
Routing

Using Maps API, you can calculate optimal routes that match your own calculation criteria, are based on up-to-date map data, and take into account real-time traffic information.  Routes can be created that reflect customizable modes such as fastest, shortest, avoiding toll roads or avoiding ferries, etc.  There is also support for utilizing historical speed patterns as an optimization for routes depending on the time of day.

The routing service is initialized with a call to platform.getRoutingService() which returns an instance of H.service.RoutingService() in the initInstance() function:

function initInstance() {
	// Code not shown
	routeService = platform.getRoutingService();
	// Code not shown
};

Leave a Reply