The use of geolocation services in enterprise apps is common. One of the most common geolocation requirements is to calculate the distance between two points. This is helpful in planning routes, determining mileage, forecasting delivery schedules, and more.
The following recipe demonstrates how to calculate the distance between two addresses. This distance measurement is done using a direct distance, not a routing calculation such as those used for walking or driving. The following screenshots illustrate this recipe running on both an iPhone and an Android device.
This recipe uses both CommonJS and native modules. These can be downloaded from the source code provided by the book, or individually through the links provided in the See also section at the end of this recipe. Simply copy the forwardGeo.js
file into the Resources
folder of your project and then copy the modules
folder into your project as shown in the following screenshot:
After copying the file and folder mentioned here, you will need to click on your tiapp.xml file in Titanium Studio and add a reference to the bencoding.basicgeo
module as shown in the following screenshot:
Once you have added native and CommonJS modules to your project, you next need to create your application namespaces in the app.js
file and use require
to import the module into your code as the following code snippet demonstrates:
//Create our application namespace var my = { forward : require('forwardGeo') };
The following startAddress
and endAddress
objects are added to the app namespace. These objects will be used to create the address information and coordinate state for this recipe.
my.startAddress = { needRefresh:true,lat:40.748433, lng:-73.985656, address:'350 5th Ave New York, NY 10118' }; my.endAddress = { needRefresh:false, lat:40.75773, lng:-73.985708, address:'1560 Broadway, New York, NY 10036' };
The following code snippet describes how to create the UI shown in this recipe's earlier screenshots:
Ti.UI.Window
to which all visual elements will be attached.var win = Ti.UI.createWindow({ backgroundColor: '#fff', title: 'Geo Distance Recipe', barColor:'#000',fullscreen:false });
txtStartAddress Ti.UI.TextField
is created to allow the user to enter a starting address.var txtStartAddress = Ti.UI.createTextField({ hintText:'enter starting address', value: my.startAddress.address, height:40, left:5, right:5, top:55, borderStyle:Ti.UI.INPUT_BORDERSTYLE_ROUNDED }); win.add(txtStartAddress);
txtEndAddress Ti.UI.TextField
is created to allow the user to enter a destination address.var txtEndAddress = Ti.UI.createTextField({ hintText:'enter destination address', value: my.endAddress.address, height:40, left:5, right:5, top:125, borderStyle:Ti.UI.INPUT_BORDERSTYLE_ROUNDED }); win.add(txtEndAddress);
findButton Ti.UI.Button
is then added to the Ti.UI.Window
later in this recipe. This button will be used to perform the distance calculation.var findButton = Ti.UI.createButton({ title:'Calculate Distance between', height:40, left:5, right:5, top:180 }); win.add(findButton);
This recipe uses the geo
object to perform distance and address lookup operations.
var geo ={
distanceInUnits
uses the Haversine formula and computes the direct distance in kilometers or meters between two sets of coordinates.distanceInUnits: function(lat1, lng1, lat2, lng2){ var rOfEarth = 6371; var dLat = (lat2-lat1)*Math.PI/180; var dLon = (lng2-lng1)*Math.PI/180; var a = Math.sin(dLat/2) * Math.sin(dLat/2) + Math.cos(lat1*Math.PI/180) * Math.cos(lat2*Math.PI/180) * Math.sin(dLon/2) * Math.sin(dLon/2); var c = 2 * Math.asin(Math.sqrt(a)); var distance = rOfEarth * c;
return { distance: ((distance < 1) ? (distance * 1000) : distance), unit: ((distance < 1) ? 'm' : 'km') }; },
findLocations
method is used to obtain the coordinates for the addresses provided.findLocations : function(callback){
onFinish
function is the callback method provided to the forwardGeo
function. The e
parameter provides the starting and ending address coordinates.function onFinish(e){ if(!e.success){ alert(e.message); return; }
The forwardGeo e.start
and e.end
results are assigned to the my.startAddress
and my.endAddress
properties. The callback method is then executed, so the distance calculation can be performed.
my.startAddress = e.start; my.endAddress = e.end; callback(); };
forwardGeo
method is called to obtain the coordinates for the my.startAddress
and my.endAddress
objects. As discussed earlier, the geolocation results are provided to the onFinish
callback method as the following code snippet demonstrates:my.forward.forwardGeo(my.startAddress, my.endAddress,onFinish); } };
When the user presses the findButton
and the click event is fired, the recipe will perform a distance calculation between the two addresses entered.
findButton.addEventListener('click',function(e){
if(!my.forward.isSupported()){ alert('Forward Geocoding is not supported'), return; }
findDistance
method is used to make the distance calculation method call and format the provided results.function findDistance(){
distanceInUnits
method using the latitude and longitude information for each address.var result = geo.distanceInUnits( my.startAddress.lat,my.startAddress.lng, my.endAddress.lat,my.endAddress.lng);
distance
variable is rounded to the first three decimal places. If it is in meters, the full value will be displayed.if(result.unit=='km'){ result.distance = result.distance.toFixed(3); } distanceLabel.text = result.distance + " " + result.unit + " between addresses"; };
geo.findLocation
method is called. The findDistance
method is provided as the callback method to the findLocations
function so that the distance calculation can be performed after the coordinates are obtained.if(my.startAddress.needRefresh || my.endAddress.needRefresh){ geo.findLocations(findDistance); }else{
findDistance
method is called directly to perform the distance calculation.findDistance(); } });
3.20.224.107