day5

Seven days with Titanium – day 5 – GPS and Maps

This doesn’t need any kind of introduction. You can use the location on the devices to find the user’s place and act accordingly. One thing good to know is that this needs the approval of the user, and for iOs > 3.2 you need to set a purpose property to let Apple know what you need it for.

Titanium.Geolocation.purpose = "GPS user coordinates";

How geolocation works

When you start the app the coordinates are the ones cached on the device, in other words the ones detected at the last time you used the geolocation on your device. Detecting the current position takes time so if you have an app based on geolocation you might want to take this in account to improve the user experience and avoid to get false results.

Titanium.Geolocation provides the needed methods to manage geolocation.

In general the most used method is getCurrentPosition that gives you the current position and fires once and the location event that triggers repeatedly on the location change. To be more clear think you want to log a route the user follow: when the app starts you get its start position then while walking you can get the points of the route with a adjustable granularity.

 
Titanium.Geolocation.distanceFilter = 10; // set the granularity of the location event
 
	Titanium.Geolocation.getCurrentPosition(function(e)
	{
		if (e.error)
		{
                // manage the error
                return;
		}
 
		var longitude = e.coords.longitude;
		var latitude = e.coords.latitude;
		var altitude = e.coords.altitude;
		var heading = e.coords.heading;
		var accuracy = e.coords.accuracy;
		var speed = e.coords.speed;
		var timestamp = e.coords.timestamp;
		var altitudeAccuracy = e.coords.altitudeAccuracy;
 
                // we use the above data the way we need it
	});
 
	Titanium.Geolocation.addEventListener('location',function(e)
	{
		if (e.error)
		{
                // manage the error
		return;
		}
 
		var longitude = e.coords.longitude;
		var latitude = e.coords.latitude;
		var altitude = e.coords.altitude;
		var heading = e.coords.heading;
		var accuracy = e.coords.accuracy;
		var speed = e.coords.speed;
		var timestamp = e.coords.timestamp;
		var altitudeAccuracy = e.coords.altitudeAccuracy;
 
               // again we use the gathered data
      });

There are some other methods that can be used like reverseGeocoder, forwardGeocoder, and getCurrentHeading – for compass. Because not all the devices have the GPS location (like iPod) or the compass and because the user can have the location services disabled you have to check if it exists, if it’s enabled and then let the user know about this.

As the documentation page is not complete yet, I suggest you to take a look at the geolocation example that shows very well how to use this.

Maps

The maps are created using the Titanium.Map methods. The maps are a little bit complicated but allows you to do some real nice interfaces. You can use a Mapview and add a route to it, or pins(markers) and to the pins to attach popups with images, titles, even “links” o another windows for a more detailed view of the specified place or whatever you may need.

Create a map

var mapview = Titanium.Map.createView({
	top:20,
	height:300,
	mapType: Titanium.Map.STANDARD_TYPE,
	region:{latitude:33.74511, longitude:-84.38993, latitudeDelta:0.5, longitudeDelta:0.5},
	animate:true,
	regionFit:true,
	userLocation:true
});

Nothing complicated: the constructor can receive different arguments including the annotations (pins), but of course you will have to declare it first.

And this is done like this:

var apple = Titanium.Map.createAnnotation({
	latitude:37.33168900,
	longitude:-122.03073100,
	title:"Steve Jobs",
	subtitle:'Cupertino, CA',
	pincolor:Titanium.Map.ANNOTATION_GREEN,
	animate:true,
	rightButton: 'apple_logo.jpg',
	myid:2 // CUSTOM ATTRIBUTE THAT IS PASSED INTO EVENT OBJECTS
});
 
var atlanta = Titanium.Map.createAnnotation({
		latitude:33.74511,
		longitude:-84.38993,
		title:"Atlanta, GA",
		subtitle:'Atlanta Braves Stadium\nfoo',
		animate:true,
		leftButton:'atlanta.jpg',
		rightButton: Titanium.UI.iPhone.SystemButton.DISCLOSURE,
		myid:3 // CUSTOM ATTRIBUTE THAT IS PASSED INTO EVENT OBJECTS
	});

and the map constructor gets

	annotations:[atlanta,apple]

or later you can add this annotation using

	mapview.addAnnotation(atlanta);

Map events

One thing you need to know is that the events are registered at the map level. So you cannot get a click event on a pin. You will have to get the click event of the mapview ad use the clicksource and the custom property (myId) properties to detect the annotation and what has been clicked (pin, leftbutton, rightbutton, title, subtitle)

	if (evt.source.myid == 3 && evt.clicksource == 'rightButton') {
        // do your stuff
        }

MapRoute

Another thing you can do with a map is to add a route (iOs only for now). Basically you can draw a line on the map specifying the points (gpd point) it needs to pass through.

A route can look like this:

var route = {
	name:"some name",
	points:points,
	color:"red",
	width:2
};

Where points it’s an array of objects containing latitude and longitude coordinates.

screen capture showing a google map on an iphone screen

Example – add a route to a Mapview

Below is an example that adds a route to a mapview using some readymade coordinates. It will generate something similar to the screenshot in the right.

var center = {latitude:42.30,longitude:-71.18,latitudeDelta:0.03, longitudeDelta:0.1};
 
var mapview = Titanium.Map.createView({
	mapType: Titanium.Map.STANDARD_TYPE,
	region: center,
	animate:true,
	regionFit:true
});
 
points = [
	{latitude:42.31,longitude:-71.11},
	{latitude:42.32,longitude:-71.13},
	{latitude:42.31,longitude:-71.22},
	{latitude:42.28,longitude:-71.26}
]
 
// route object
var route = {
	name:"some name",
	points:points,
	color:"#00f",
	width:2
};
 
// add a route
mapview.addRoute(route);

What next?

A good exercise would be maybe to create an application that it’s watching your position while you are driving or walking and display it on a map. All you would have to do is to use the location event and use the returned value to append a new item to the points array.

Anybody wanna try ? :)

Check the Spanish version of this post:
Siete días con Titanium – día 5 – GPS y Mapas

9 thoughts on “Seven days with Titanium – day 5 – GPS and Maps”

  1. Hi

    Tracking a route is not as easy as it appears to be!
    The route feature on Titanium is very buggy! Like you see on this thread (http://developer.appcelerator.com/question/106081/map-route-disappears-when-zoomed-in)
    I’ve already found a solution. Split the route to multiple routes and add them with different names!

    The second problem is http://developer.appcelerator.com/question/62391/iphone-route-only-displayed-when-user-moves-the-map

    If you want to add a very large route, the user doesn’t see the route until he moves the map. A temporary fix is to set regionFit.

    If you want to add new points to the route while tracking, the route will not render the route properly.
    To fix that I add a NEW route for every new tracked location. The length of each route is only 2 points! (IMPORTANT: You have to name each route different!)

    Hope this helps!
    Best regards
    Felix

  2. This is pretty awesome. I just found this series today and I’m already halfway through it :-)

    My javascript skills are a little rusty but I do plan on (re)learning a lot of things and am already looking forward the next installment in the series.

  3. I’ve tried using the code of the KitchenSink example into a separate small application and realized the following. If you keep it like it is, including the heading event, the accuracy is great close to 10m, depending on you actual location. If you remove the heading event (as you suggest because not all devices have compass), the accuracy goes to 500m or more. Any ideas?

  4. @peter, vassilis I honestly have no idea why it’s behaving like this. Maybe the best approach is to detect if the device has compass and use the heading to improve the accuracy.

Comments are closed.