×
Namespaces

Variants
Actions
Revision as of 18:16, 12 September 2013 by jasfox (Talk | contribs)

Journey Planner using HERE Maps

From Nokia Developer Wiki
Jump to: navigation, search

This article shows how to make web and mobile based Journey-planning applications that use HERE Maps.

Archived.pngArchived: This article is archived because it is not considered relevant for third-party developers creating commercial solutions today. If you think this article is still relevant, let us know by adding the template {{ReviewForRemovalFromArchive|user=~~~~|write your reason here}}.

The article is believed to be still valid for the original topic scope.

Article Metadata
Code Example
Source file: planmyroute
Article
Keywords: HERE Maps, Locations
Created: jackdenial (19 Dec 2011)
Last edited: jasfox (12 Sep 2013)

Contents

Introduction

Most mapping applications provide solutions around "personal" use cases:

  • I use maps when I travel to new places
  • I use maps to find new coffee shops in town to get privacy with my girl friend.
  • I love to play with maps when I am travelling

The Journey Planner application showcases the power of HERE Maps using a more "business-oriented" concept - a journey planner for a transportation/courier business.

Lets dive into the functionality overview and see whether it is really useful or not.

The application is divided into two parts:

  1. Web Based (Non-mobile) - Journey Planner:
    The "Journey Manager" of XYZ Transportation Company will be using this application. He will login to the web application using a master account. From here, he will be able to manage their existing Journeys (basically routes) and design new Journeys (Will come to the technical part later below). All Journeys will be saved in a database (coordinates of all waypoints). Here, the Journey Manager's responsibility is to assign the Journey (route) to individual users. That's it for now for the Journey Planner part.
  2. Mobile Application / Mobile Web - Journey Retriever:
    The "Journey Executor" (basically truck driver) can retrieve all Journeys, assigned to him by the Journey Manager, in his/her mobile. What else? You know the rest. Based on the schedule and priority the "Journey Executor" will follow/execute the journey. Whenever internet is available, this application will also update position of the driver(user) on the server so Journey Planner can keep an eye on the status of the Journey.

Requirements

To develop and implement this concept application into real world, you would require following skills:

  • Knowledge of web technologies like PHP/ASP/.NET/JSP/ROR
  • Knowledge of Database like MySQL/MSSQL or whatever you prefer to use.
  • A web server, supporting the web technology and the database chosen by you to develop the application
  • Passion to discover new things

User-interface overview

After login into the website, you will see all the routes planned by you. You can click the "View" link to view the route on Nokia Map. Clicking on "Edit" will open the route for editing. If not click on the "plan a new Route now" link, which will open up a fresh map to design your journey route.

Journey List.jpg

Below is the screenshot of Route Planner, you can drag "start point/(1)", "end point/(2)" or the route (highlighted in blue) to design and plan your journey. Nokia Map will automatically identify the shortest route and will display the path within milliseconds.

Route editor.jpg

Now, here is the route viewer. This will load the designed route on the page with minimum components. Basically, the objective of this page is to track the route while driving/walking. I haven't implemented GPS tracking in this yet. But, I will do this next month. Of course you can contribute. :)

Route viewer.jpg

User-interface design

The main component of this application is a route planner. The best way to understand the route planner function is to understand the example provided in Nokia play ground: http://api.maps.nokia.com/2.1.0/playground/index.html

The example loads a map having a draggable route on it starting from 1 to 2. Here, an existing route can be changed by dragging one of the markers to a different position, once you stop dragging a marker the new route will be automatically calculated and redrawn. One can add more markers by holding down "CTRL" key and click anywhere on the map. Removing a marker is done by holding down the "CTRL" key and clicking on an existing marker.

Now, to create the route planner page, I will make few changes in the above Nokia example.

I am adding few javascript variables at the beginning of the script.

// a flag to identify, whether the map is loading for first time for a new map creation.
var loadingflag = <?php echo $new ?>;
// Maximum number of waypoints
var max_marker = 100;
// Route ID currently being edited, if it is 0 its a new map.
var route_id = <?php echo $id ?>;
// Route map to store and display
var routename = '<?php echo $routename ?>';
// Complete path(waypoints) will be sotred in this variable
var route_path = '<?php echo $route ?>';
 
var mapContainer = document.getElementById("mapContainer");

Above javascript variables are assigned with the values provided by the PHP (server side script) variables depending on the database values.

Nokia Map Playground has a very good script of creating tiny window on top of a Map. I have modified the note window to provide "Save Route" button to the user and to show other details. Screenshot provided above (route editor).

var noteContainer = new NoteContainer({
id:"movingUi",
parent:document.getElementById("uiContainer"),
// At the time of loading, if the page is being edited we will show the routename as the Route name and if its a new route we will show "New Route"
title:"<?php if ($routename == "") {
echo "
New Route";
} else {
echo $routename;
} ?>"
,
content:'Search: <input id="place" /><br /><input id="findRoute" role="button" type="button" value="Search Place"/><input id="saveRoute" role="button" type="button" value="Save Route"/><br /><br />Approx Distance:<span id="approxDist"></span><br /> <a href="/journeys/jlist">Back to routes</a>'
});

The above script generated window contains a facility to search a location. For that I have added following JavaScript code:

var searchTerm,
resultSet,
/* We define a proximity object which we will pass to the Search Manager
* to set the center of the search and the radius around that center
* in which we would like to perform the search
*/

proximity = {
center:new nokia.maps.geo.Coordinate(52.51, 13.4),
radius:1500 // search radius defined in meters
};
 
var searchManager = new nokia.maps.search.Manager();
searchManager.addObserver("state", function (observedManager, key, value) {
// If the search has finished we can process the results
if (value == "finished") {
// We check that at least one location has been found
if (observedManager.locations.length > 0) {
// Remove results from previous search from the map
if (resultSet) map.objects.remove(resultSet);
// Convert all found locations into a searchResultSet creating markers for every found location
resultSet = (new nokia.maps.search.component.SearchResultSet(observedManager.locations)).container;
// Next we add the marker(s) to the map's object collection so they will be rendered onto the map.
//map.objects.add(resultSet);
// We zoom the map to a view that encapsulates all the markers into map's viewport.
map.zoomTo(resultSet.getBoundingBox(), false);
}
} else if (value == "failed") {
alert("The search request failed.");
}
});
var findRoute = document.getElementById('findRoute');
findRoute.onclick = function () {
searchManager.search(document.getElementById('place').value);
}

The tiny window also contains "Save Route" button. To make the button functional I have added following code:

var saveRoute = document.getElementById('saveRoute');
saveRoute.onclick = function () {
while (routename == "")
routename = prompt("Please enter Route Name", "");
ajaxTalk();
};

To save the planned route on the server, we have to write Ajax code. i.e. ajaxTalk(); function.

function ajaxTalk() {
var xmlhttp;
if (window.XMLHttpRequest) {// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp = new XMLHttpRequest();
}
else {// code for IE6, IE5
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
route_id = parseInt(xmlhttp.responseText);
document.getElementsByClassName("title")[0].innerHTML = "<h1>" + routename + "</h1>";
alert('Route has been successfully saved');
}
}
}
//Storing the Map details using Ajax
xmlhttp.open("GET", "/journeys/store/" + route_id + "/" + routename + "/" + escape(route_path), false);
xmlhttp.send();
}

To build the route, we need to change the updateRoute method of waypoints class

   updateRoute = function (oldValue, newValue) {
if (markers.length > 1) {
waypoints.coords = [];
if (loadingflag == false) {
//If not loading first time, reset the route to redraw it on map
route_path = "";
}
// reset the distance variable to calculate the distance from beginning
distance = 0;
for (var i = 0; i < markers.length; i++) {
waypoints.coords.push(markers[i].coordinate);
if (loadingflag == false) {
// building a string with route points (place coordinates) to further store it.
route_path += i.toString() + "la~" + markers[i].coordinate.latitude + ";" + i.toString() + "lo~" + markers
 
[i].coordinate.longitude + ";;";
try {
// calculating the distance between two waypoints and finally the route
distance += waypoints.coords[i].distance(waypoints.coords[i - 1]);
} catch (e) {
}
}
}
if (distance > 0) {
// Converting the distance to KMs from Meters.
distance = parseInt(distance / 1000);
}
document.getElementById("approxDist").innerHTML = distance.toString() + " KM";
max_marker = markers.length;
loadingflag = false;
router.clear();
router.calculateRoute(waypoints, mode.slice(0)); //pass a copy of the mode
}
}

To load the route or to reset the route on the map at the end we have to add following JavaScript code:

if (loadingflag == true && route_path.length > 0) {
loadingflag = false;
rp = route_path.split(';;');
 
//Setting Up the points and paths :)
for (var j = 0; j < rp.length; j++) {
 
if (!rp[j])
break;
rp[j] = rp[j].split(';');
 
if (!rp[j][0])
break;
 
rp[j][0] = rp[j][0].split('~');
rp[j][1] = rp[j][1].split('~');
 
var la = rp[j][0][1];
var lo = rp[j][1][1];
map.set("center", new nokia.maps.geo.Coordinate(parseFloat(la), parseFloat(lo)));
var start = createWaypointMarker({
latitude:parseFloat(la),
longitude:parseFloat(lo)
});
 
start.set("visibility", true);
 
 
}
loadingflag = false;
updateRoute();
} else {
var start = createWaypointMarker({
latitude:23.14,
longitude:72.42
});
start.set("visibility", true);
 
var end = createWaypointMarker({
latitude:23.16,
longitude:72.40
});
end.set("visibility", true);
}
updateRoute();

Above code interprets the route waypoints coordinates stored in the database and redesign the map accordingly. If it's a fresh map, it provides a short route from where you can decide and design your own route.

Database Design to Store

There will be two database tables will be used for Data storage:

  • Users
Field Name Field Type(length) Default Value Is NULL? Description
user_id integer Auto Increment NOT NULL To generate and store unique identity number for each user
username varchar(25) NOT NULL To store username.
password varchar(42) NOT NULL To store password for the user.

We should also add user_type field to identify and authorize the user for special privileges. But, this article is for understanding purpose so skipping it for now.

  • Journeys
Field Name Field Type(length) Default Value Is NULL? Description
journey_id integer Auto Increment NOT NULL To generate and store unique identity number for each journey
journeyname varchar(50) NOT NULL To store journey name.
route varchar(500) NOT NULL To store Journey route.
assignedto integer 0 NULL To store the user's unique id, to whom the Journey is assigned.

Yes, certainly we can assign a journey to multiple users but for now lets focus on maps.

Developing server-side scripts

I am skipping here the user registration and login page part, as it is very well known to the world. You can easily understand and learn it from the sample source code provided.

Login.jpgRegistration.jpg

Here, I am providing a brief code of server script (JourneysController.php), which is further explained below. The code is with respect to CakePHP framework.

Code Snippet:

<?php
class JourneysController extends AppController {
 
function jlist(){
$uid = (int)$this->Session->read("userid");
if($uid==0)
$this->redirect("/");
$journeys = $this->Journey->findAllByAssignedto($this->Session->read("userid"));
$this->set('journeys',$journeys);
 
}
 
function plan($id=0){
$uid = (int)$this->Session->read("userid");
if($uid==0)
$this->redirect("/");
$this->layout='ajax';
if($id==0){
$this->set("new","false");
$this->set("id",$id);
$this->set("journeyname","");
$this->set("route","");
}else{
$journey= $this->Journey->findById($id);
if($journey['Journey']['assignedto']!=$uid)
$this->redirect("/");
if($journey){
$this->set("new","true");
$this->set("id",$id);
$this->set("journeyname",$journey['Journey']['journeyname']);
$this->set("route",$journey['Journey']['route']);
}else{
$this->set("new","true");
$this->set("id",$id);
$this->set("journeyname","");
$this->set("route","");
}
}
}
 
function view($id=0){
$uid = (int)$this->Session->read("userid");
if($uid==0)
$this->redirect("/");
$this->layout='ajax';
if($id==0){
$this->redirect("/");
}else{
$journey= $this->Journey->findById($id);
if($journey['Journey']['assignedto']!=$uid)
$this->redirect("/");
if($journey){
$this->set("new","true");
$this->set("id",$id);
$this->set("journeyname",$journey['Journey']['journeyname']);
$this->set("route",$journey['Journey']['route']);
}else{
$this->redirect("/");
}
}
}
 
function store($id,$journeyname,$route=""){
$uid = (int)$this->Session->read("userid");
if($uid==0)
exit;
 
$this->layout='ajax';
 
if($id==0)
$this->Journey->create();
else
$this->Journey->id=$id;
$this->Journey->data['Journey']['journeyname']=$journeyname;
$this->Journey->data['Journey']['route']=$route;
$this->Journey->data['Journey']['assignedto']=$this->Session->read("userid");
$this->Journey->save($this->Journey->data);
echo $this->Journey->id;
exit;
 
}
}
?>

Listing Journeys : The jlist() function fetches all the routes (journeys) associated with the logged in user and show it on the page. (see http://planmyroute.info/journeys/jlist)

Creating/Editing a Map : The plan() function takes a parameter $id. If it is 0 (default value) or not provided through the URL ( see http://planmyroute.info/journeys/plan) the function sets default values to the variables and the default route is presented to the user for new route creation. If the $Id variable is provided the function will fetch the data related to the id from the database and present the same route on the map to the user for further edition.

Viewing the Map : The function, view(), does the same thing explained above except providing the capability of editing the route.

Storing the Route : The last function, store(), catches data provided through the ajax request if the route_id is 0 then it will create a new record ( route entry) and will store the value other wise it will overwrite existing record with the new route data.

Demo Website

You can feel the live demo at http://www.planmyroute.info.

Source Code

You can retrieve the source code of this application from http://projects.developer.nokia.com/planmyroute. You just need to download WAMP and place all the source files to the c:\wamp\www folder. You will also need to setup the database by executing database.sql file in your mysql database.

Important Notes

  • Don't forget to use the API Key, provided by Nokia, in your application
  • The Code samples provided by me is just for your education purpose, please review the code twice before using it.
386 page views in the last 30 days.
×