Modifying spec file to rely on Common module, and copying the code from it once insta...
[profile/ivi/html5_UI_Nav.git] / js / main.js
1 /*jshint eqnull:true*/
2 /*global google*/
3
4 /**
5  * Navigation application allows user to use Google Maps to navigate around in predefined set of waypoints in Places library with Text-To-Speech feature
6  * (via {{#crossLink "Speech"}}{{/crossLink}} object). Nvigation doesn't use GPS but updates position of marker along the route in periodic intervals.
7  * Default navigation waypoints are defined by:
8  *
9  * * start point: {{#crossLink "NavigationGoogle/originAddress:property"}}{{/crossLink}} property
10  * * end point: {{#crossLink "NavigationGoogle/destinationAddress:property"}}{{/crossLink}} property
11  *
12  * To add additional places or update existing ones please change property {{#crossLink "NavigationGoogle/places:property"}}{{/crossLink}}.
13  *
14  * Hover and click on elements in images below to navigate to components of Navigation application.
15  *
16  * <img id="Image-Maps_1201312180420487" src="../assets/img/navigation.png" usemap="#Image-Maps_1201312180420487" border="0" width="650" height="1148" alt="" />
17  *   <map id="_Image-Maps_1201312180420487" name="Image-Maps_1201312180420487">
18  *     <area shape="rect" coords="0,0,573,78" href="../classes/topbaricons.html" alt="Top bar icons" title="Top bar icons" />
19  *     <area shape="rect" coords="0,994,644,1147" href="../classes/bottompanel.html" alt="Bottom panel" title="Bottom panel" />
20  *     <area shape="rect" coords="521,133,645,186" href="../classes/Library.html" alt="Places library" title="Places library"    />
21  *     <area shape="poly" coords="1,78,512,80,514,191,648,192,646,291,0,292," href="../classes/NavigationGoogle.html#method_updateNavigationPanel" alt="Navigation panel" title="Navigation panel"   />
22  *     <area shape="poly" coords="1,298,648,301,644,890,530,887,528,970,648,969,647,1022,3,1022," href="../classes/NavigationGoogle.html#method_animate" alt="Animate along waypoints" title="Animate along waypoints"   />
23  *     <area shape="rect" coords="530,888,631,965" href="../classes/NavigationGoogle.html#method_switchMapSatelitteView" alt="Switch map mode" title="Switch map mode"    />
24  *   </map>
25  * @module NavigationGoogleApplication
26  * @main NavigationGoogleApplication
27  * @class NavigationGoogle
28  */
29
30 /**
31  * Reference to instance of class object this class is inherited from dataModel {@link CarIndicator}.
32  * @property carInd {Object}
33  */
34 var carInd;
35
36 /**
37  * Array of destination addresses used in places library list.
38  * @property places {Object[String]}
39  * @for NavigationGoogle
40  */
41 var places = [
42               {destinationAddress: "Golden Gate Bridge, San Francisco, CA 94129, USA"},
43               {destinationAddress: "Coit Tower, San Francisco, CA 94133, USA"},
44               {destinationAddress: "The Exploratorium, Pier 15, San Francisco, CA 94111, USA"},
45               {destinationAddress: "Steinhart Aquarium, 55 Music Concourse Drive, San Francisco, CA 94122, USA"}
46              ];
47
48 /**
49  * Holds origin address value.
50  * @for NavigationGoogle
51  * @property originAddress {String}
52  */
53 var originAddress = "Fell Street, San Francisco, CA, United States";
54
55 /**
56  * Holds destination address value.
57  * @for NavigationGoogle
58  * @property destinationAddress {String}
59  */
60 var destinationAddress = "75 Hagiwara Tea Garden Dr San Francisco, CA 94118";
61
62 /**
63  * Holds origin object value.
64  * @for NavigationGoogle
65  * @private
66  * @property origin {String}
67  */
68 var origin = null;
69
70 /**
71  * Holds destination object value.
72  * @for NavigationGoogle
73  * @private
74  * @property destination {String}
75  */
76 var destination = null;
77
78 /**
79  * Holds map object.
80  * @for NavigationGoogle
81  * @private
82  * @property map {Object}
83  */
84 var map;
85
86 /**
87  * Holds geocoder object.
88  * @for NavigationGoogle
89  * @private
90  * @property geocoder {Object}
91  */
92 var geocoder = null;
93
94 /**
95  * Holds direction service method.
96  * @for NavigationGoogle
97  * @private
98  * @property directionsService {Object}
99  */
100 var directionsService = null;
101
102 /**
103  * Holds direction renderer method.
104  * @for NavigationGoogle
105  * @private
106  * @property directionRenderer {Object}
107  */
108 var directionRenderer = null;
109
110 /**
111  * Holds polyline method.
112  * @for NavigationGoogle
113  * @private
114  * @property polyline {Object}
115  */
116 var polyline = null;
117
118 /**
119  * Holds route object method.
120  * @for NavigationGoogle
121  * @private
122  * @property route {Object}
123  */
124 var route = null;
125
126 /**
127  * Holds marker object.
128  * @for NavigationGoogle
129  * @private
130  * @property marker {Object}
131  */
132 var marker = null;
133
134 /**
135  * Holds direction instructions objects array.
136  * @for NavigationGoogle
137  * @private
138  * @property instructions {Object[]}
139  */
140 var instructions = [];
141
142 /**
143  * Holds status if metric system is used.
144  * @for NavigationGoogle
145  * @private
146  * @property useMetricSystem {Boolean}
147  */
148 var useMetricSystem = false;
149
150 /**
151  * Holds step value in meters.
152  * @for NavigationGoogle
153  * @private
154  * @property step {Integer}
155  */
156 var step = 10; // metres
157
158 /**
159  * Holds tick value in milliseconds.
160  * @for NavigationGoogle
161  * @private
162  * @property tick {Integer}
163  */
164 var tick = 200; // milliseconds
165
166 /**
167  * Holds distance value.
168  * @for NavigationGoogle
169  * @private
170  * @property distance {Integer}
171  */
172 var polDistance = 0;
173
174 /**
175  * Holds remaining distance value.
176  * @for NavigationGoogle
177  * @private
178  * @property remainingDistance {Integer}
179  */
180 var remainingDistance = 0;
181
182 /**
183  * Holds remaining step distance value.
184  * @for NavigationGoogle
185  * @private
186  * @property remainingStepDistance {Integer}
187  */
188 var remainingStepDistance = 0;
189
190 /**
191  * Holds remaining time value.
192  * @for NavigationGoogle
193  * @private
194  * @property remainingTime {Integer}
195  */
196 var remainingTime = 0;
197
198 /**
199  * Holds route duration value.
200  * @for NavigationGoogle
201  * @private
202  * @property routeDuration {Integer}
203  */
204 var routeDuration = 0;
205
206 /**
207  * Holds average speed value.
208  * @for NavigationGoogle
209  * @private
210  * @property averageSpeed {Integer}
211  */
212 var averageSpeed = 0;
213
214 /**
215  * Holds instruction index value.
216  * @for NavigationGoogle
217  * @private
218  * @property instructionIndex {Integer}
219  */
220 var instructionIndex = 0;
221
222 /**
223  * Holds status value if instruction changed.
224  * @for NavigationGoogle
225  * @private
226  * @property instructionChanged {Boolean}
227  */
228 var instructionChanged = true;
229
230 /**
231  * Holds animation timer object.
232  * @for NavigationGoogle
233  * @private
234  * @property timerHandle {Object}
235  */
236 var timerHandle;
237
238 /**
239  * Instance of class Bootstrap, this class provides unified way to boot up the HTML applications by loading shared components in proper order.
240  * * {{#crossLink "Bootstrap"}}{{/crossLink}}
241  *
242  * @property bootstrap {Object}
243  */
244 var bootstrap;
245
246 /**
247  * Strips the HTML code removing all the HTML marks from it.
248  * @method strip
249  * @for NavigationGoogle
250  * @private
251  * @param html {String} HTML code
252  */
253 function strip(html) {
254         "use strict";
255     var tmp = document.createElement("DIV");
256     tmp.innerHTML = html;
257     return tmp.textContent || tmp.innerText;
258 }
259 /**
260  * Method switches between satellite or classic map view.
261  * @method switchMapSatelitteView
262  * @for NavigationGoogle
263  */
264 function switchMapSatelitteView() {
265         "use strict";
266         /*global google */
267         if (map.getMapTypeId() === google.maps.MapTypeId.ROADMAP) {
268                 map.setMapTypeId(google.maps.MapTypeId.SATELLITE);
269                 $(".mapIcon").css('display', 'none');
270                 $(".satelitteIcon").css('display', 'inherit');
271         } else if (map.getMapTypeId() === google.maps.MapTypeId.SATELLITE) {
272                 map.setMapTypeId(google.maps.MapTypeId.ROADMAP);
273                 $(".satelitteIcon").css('display', 'none');
274                 $(".mapIcon").css('display', 'inherit');
275         } else {
276                 console.log("Othere map type is " + map.getMapTypeId());
277         }
278         console.log(map.getMapTypeId());
279 }
280
281 /**
282  * NMethod changes navigation arrow based on instruction text.
283  * @method changeNavigationArrow
284  * @for NavigationGoogle
285  * @param instructionText {String} Instruction text.
286  */
287 function changeNavigationArrow(instructionText) {
288         "use strict";
289         var turnRight = instructionText.indexOf("right");
290         var turnLeft = instructionText.indexOf("left");
291
292         if (turnRight > 0 && turnRight < 10) {
293                 //"left" or "right" is on the beginning of instruction step
294                 $("#turnArrow").css("background-image", "url('images/icon_arrow_right.png')");
295         } else if (turnLeft > 0 && turnLeft < 10) {
296                 //"left" or "right" is on the beginning of instruction step
297                 $("#turnArrow").css("background-image", "url('images/icon_arrow_left.png')");
298         } else {
299                 $("#turnArrow").css("background-image", "url('images/icon_arrow_straight.png')");
300         }
301 }
302
303 /**
304  * Method changes format of distance value text.
305  * @method formatMeters
306  * @for NavigationGoogle
307  * @param meters {Integer} Distance value in meters.
308  * @param fontSize {Integer} Font size.
309  * @return {String} Distance in meters width changed font format.
310  */
311 function formatMeters(meters, fontSize) {
312         "use strict";
313         if (meters > 500) {
314                 return (Math.round(meters / 100)) / 10 + "<span class=" + fontSize + ">KM</span>";
315         } else {
316                 return Math.round(meters) + "<span class=" + fontSize + ">m</span>";
317         }
318 }
319
320 /**
321  * Method converts distance from meters to feets and changing formats of distance value text.
322  * @method convertMetersToFeetsMiles
323  * @for NavigationGoogle
324  * @param meters {Integer} Distance value in meters.
325  * @param fontSize {Integer} Font size.
326  * @return {String} Distance in feets width changed font format.
327  */
328 function convertMetersToFeetsMiles(meters, fontSize) {
329         "use strict";
330         var feets = meters * 3.280839895;
331         if (feets > 528) {
332                 return (Math.round(feets / 528)) / 10 + "<span class=" + fontSize + ">MI</span>";
333         } else {
334                 return Math.round(feets) + "<span class=" + fontSize + ">ft</span>";
335         }
336 }
337
338 /**
339  * Method converts seconds to time.
340  * @method secondsToTime
341  * @for NavigationGoogle
342  * @param secs {Integer} Time value in seconds.
343  * @return {Object} Time in object with hours, minutes and second separated format.
344  */
345 function secondsToTime(secs) {
346         "use strict";
347         var hours = Math.floor(secs / (60 * 60));
348
349         var divisorForMinutes = secs % (60 * 60);
350         var minutes = Math.floor(divisorForMinutes / 60);
351
352         var divisorForSeconds = divisorForMinutes % 60;
353         var seconds = Math.ceil(divisorForSeconds);
354
355         var obj = {
356                         "h" : hours,
357                         "m" : minutes,
358                         "s" : seconds
359                 };
360         return obj;
361 }
362
363 /**
364  * Method provides leading 0 to time value.
365  * @method addLeading0ToTime
366  * @for NavigationGoogle
367  * @param time {Integer} Time value.
368  * @return time {String} Time with leading 0.
369  */
370 function addLeading0ToTime(time) {
371         "use strict";
372         if (time < 10) {
373                 return "0" + time;
374         } else {
375                 return time;
376         }
377 }
378
379 /**
380  * Method formats time to HHMM format.
381  * @method formatTimeToHHMM
382  * @for NavigationGoogle
383  * @param seconds {Integer} Time value in seconds.
384  * @return formatedTime {String} Time in format HHMM.
385  */
386 function formatTimeToHHMM(seconds) {
387         "use strict";
388         var hours = secondsToTime(seconds).h;
389         var minutes = secondsToTime(seconds).m;
390         var formatedTime;
391
392         if (hours > 0 || minutes > 0) {
393                 formatedTime = addLeading0ToTime(hours) + ":" + addLeading0ToTime(minutes);
394         } else {
395                 formatedTime = seconds + "<span class='fontSizeSmall'>s</span>";
396         }
397         return formatedTime;
398 }
399
400 /**
401  * Method adds seconds to current time.
402  * @method addSecondsToCurrentTime
403  * @for NavigationGoogle
404  * @param secs {Integer} Time value in seconds.
405  * @return result {String} Time in format HHMM.
406  */
407 function addSecondsToCurrentTime(secs) {
408    "use strict";
409    var todayDate = new Date();
410    var hours = todayDate.getHours();
411    var minutes = todayDate.getMinutes();
412    var seconds = todayDate.getSeconds();
413    var newSec = parseInt(seconds, 10) + parseInt(secs, 10);
414    var newMin;
415    var mins;
416    var sec;
417    var min;
418    var newHrs;
419
420    if (newSec > 59) {
421       mins = parseInt(newSec / 60, 10);
422       sec = newSec - mins * 60;
423       newMin = parseInt(minutes, 10) + mins;
424
425       if (newMin > 59) {
426          var hrs = parseInt(newMin / 60, 10);
427          min = newMin - (hrs * 60);
428          newHrs = parseInt(hours, 10) + hrs;
429       } else {
430          newHrs = hours;
431          min = newMin;
432       }
433    } else {
434       newHrs = hours;
435       min = minutes;
436       sec = newSec;
437    }
438
439    var format = "AM";
440
441    if (newHrs > 11) {
442       format = "PM";
443    }
444    if (newHrs > 12) {
445       newHrs = newHrs - 12;
446    }
447    if (newHrs === 0) {
448       newHrs = 12;
449    }
450    if (min < 10) {
451       min = "0" + min;
452    }
453
454    return newHrs + ":" + min + format;
455 }
456
457 /**
458  * Method update the navigation panel.
459  * @method updateNavigationPanel
460  * @for NavigationGoogle
461  */
462 function updateNavigationPanel() {
463         "use strict";
464         if (instructionChanged) {
465                 var instruction = strip(instructions[instructionIndex].instruction);
466                 console.log("Instruction changed to '" + instruction + "'.");
467                 $("#navigationPanel").html(instruction);
468                 /* global Speech*/
469                 Speech.vocalizeString(instruction);
470                 changeNavigationArrow(instruction);
471                 instructionChanged = false;
472         }
473
474         if (useMetricSystem === true) {
475                 remainingStepDistance = formatMeters(remainingStepDistance, 'fontSizeSmaller');
476         } else {
477                 remainingStepDistance = convertMetersToFeetsMiles(remainingStepDistance, 'fontSizeSmaller');
478         }
479
480         $("#distanceTo").html(remainingStepDistance);
481         $("#destinationProgress").progressBarPlugin('setPosition', (remainingDistance / polDistance) * 100);
482
483         var remainingTime = Math.round(remainingDistance / averageSpeed); //time in seconds
484         remainingTime = formatTimeToHHMM(remainingTime);        //seconds to hh:mm
485
486         if (useMetricSystem === true) {
487                 remainingDistance = formatMeters(remainingDistance, 'fontSizeSmall');
488         } else {
489                 remainingDistance =  convertMetersToFeetsMiles(remainingDistance, 'fontSizeSmall');
490         }
491
492         $("#stillToGoTimeAndDistance").html(remainingTime + " / " + remainingDistance);
493 }
494
495 /**
496  * Method animates current position along the route.
497  * @method animate
498  * @for NavigationGoogle
499  * @param d {Integer}
500  */
501 function animate(d) {
502         "use strict";
503         if (d + step > instructions[instructionIndex].distanceValue) {
504                 if (instructionIndex < instructions.length - 1) {
505                         instructionChanged = true;
506                         instructionIndex++;
507                 }
508         }
509
510         if (d > polDistance) {
511                 instructionIndex = instructions.length - 1;
512                 instructionChanged = false;
513
514                 remainingDistance = 0;
515                 remainingStepDistance = 0;
516                 remainingTime = 0;
517
518                 updateNavigationPanel();
519
520                 map.panTo(polyline.getPath().getAt(polyline.getPath().length - 1));
521                 marker.setPosition(polyline.getPath().getAt(polyline.getPath().length - 1));
522
523                 var option = {draggable: true};
524                 map.setOptions(option);
525                 return;
526         }
527
528         remainingDistance = polDistance - d;
529         remainingStepDistance = instructions[instructionIndex].distanceValue - d;
530
531         updateNavigationPanel();
532
533         var p = polyline.GetPointAtDistance(d);
534         map.panTo(p);
535         marker.setPosition(p);
536         timerHandle = setTimeout("animate(" + (d + step) + ")", tick);
537 }
538
539 /**
540  * Method starts animation.
541  * @method startAnimation
542  * @for NavigationGoogle
543  * @constructor
544  */
545 function startAnimation() {
546         "use strict";
547         var option = {
548                         draggable: false
549                 };
550         map.setOptions(option);
551
552         marker = new google.maps.Marker();
553         marker.setMap(map);
554         marker.setPosition(polyline.getPath().getAt(0));
555         map.setCenter(polyline.getPath().getAt(0));
556         polDistance = polyline.Distance();
557
558         console.log(polyline.getPath());
559         console.log(polDistance);
560         console.log(instructions);
561
562         remainingDistance = polDistance;
563         remainingStepDistance = instructions[instructionIndex].distanceValue;
564         routeDuration = route.duration.value;
565         remainingTime = routeDuration;
566         averageSpeed = (route.distance.value / routeDuration);
567
568         /* jshint camelcase: false */
569         $("#destinationAddress").html(destination.formatted_address);
570         $("#destinationAddressTown").html(destination.address_components[2].short_name + ", " + destination.address_components[3].short_name);
571         /* jshint camelcase: true */
572
573         var averageSpeedText;
574
575         if (useMetricSystem === true) {
576                 averageSpeedText = Math.round(averageSpeed * 3.6) + "<span class='fontSizeXXSmall'> km/h</span>" + ")";
577         } else {
578                 averageSpeedText = Math.round(averageSpeed * 2.2369362920544) + "<span class='fontSizeXXSmall'> MPH</span>" + ")";
579         }
580
581         $("#arrivalText").html("ARRIVAL " + addSecondsToCurrentTime(routeDuration) + " (" + averageSpeedText);
582
583         updateNavigationPanel();
584         window.setTimeout(function(){
585                 animate(0);
586                 }, 2000); // Allow time for the initial map display
587 }
588
589 /**
590  * Method renders the route.
591  * @method renderRoute
592  * @for NavigationGoogle
593  * @param origin {Object} Origin position object.
594  * @param destination {Object} Destination position object.
595  */
596 function renderRoute(origin, destination) {
597         "use strict";
598         if (directionsService === null) {
599                 directionsService = new google.maps.DirectionsService();
600         }
601
602         if (directionRenderer === null) {
603                 directionRenderer = new google.maps.DirectionsRenderer();
604         }
605
606         directionRenderer.setMap(map);
607
608         var request = {
609                         origin: origin,
610                         destination: destination,
611                         travelMode: google.maps.DirectionsTravelMode.DRIVING
612                 };
613
614         directionsService.route(request, function (response, status) {
615                 console.log(status);
616                 console.log(response);
617                 if (status === google.maps.DirectionsStatus.OK && response.routes.length) {
618                         if (response.routes && response.routes[0] && response.routes[0].legs && response.routes[0].legs[0]) {
619                                 polyline = new google.maps.Polyline({
620                                         path : []
621                                 });
622
623                                 route = response.routes[0].legs[0];
624                                 directionRenderer.setDirections(response);
625
626                                 var steps = route.steps;
627                                 var distanceStep = 0;
628                                 var j;
629                                 for (j = 0; j < steps.length; j++) {
630                                         var latLngs = steps[j].path;
631                                         distanceStep = distanceStep + (steps[j].distance.value || 0);
632
633                                         var instruction = {
634                                                         distance: (steps[j].distance || 0),
635                                                         distanceValue: distanceStep,
636                                                         instruction: (steps[j].instructions ? steps[j].instructions.trim() : "")
637                                                 };
638
639                                         instructions.push(instruction);
640                                         var k;
641                                         for (k = 0; k < latLngs.length; k++) {
642                                                 polyline.getPath().push(latLngs[k]);
643                                         }
644                                 }
645                                 startAnimation();
646                         }
647                 } else {
648                         console.log('Route calculation failed: ' + status);
649                 }
650         });
651 }
652
653 /**
654  * Starts the navigation.
655  * @method startNavigation
656  * @for NavigationGoogle
657  */
658 function startNavigation(){
659         "use strict";
660         try {
661                 if (geocoder == null) {
662                         geocoder = new google.maps.Geocoder();
663                 }
664                 geocoder.geocode({
665                         address: originAddress
666                 }, function (results, status) {
667                         if (status === "OK" && results.length) {
668                                 origin = results[0] || null;
669                                 map.setCenter(origin.geometry.location);
670                                 geocoder.geocode({
671                                         address: destinationAddress
672                                 }, function (results, status) {
673                                         if (status === "OK" && results.length) {
674                                                 destination = results[0] || null;
675
676                                                 if (origin && destination) {
677                                                         renderRoute(origin.geometry.location, destination.geometry.location);
678                                                 }
679                                         } else {
680                                                 console.log("Destination not found. Unable to get the route.");
681                                         }
682                                 });
683                         } else {
684                                 console.log("Origin not found. Unable to get the route.");
685                         }
686                 });
687         } catch (error) {
688                 console.log(error.message);
689         }
690 }
691 var bootstrap;
692 $(document).ready(function () {
693         "use strict";
694         /* global Bootstrap*/
695         bootstrap = new Bootstrap(function (status) {
696                 $("#topBarIcons").topBarIconsPlugin('init', 'navigation');
697                 $("#upNextRectangle").boxCaptionPlugin('init', 'up next');
698                 $("#destinationProgress").progressBarPlugin('init', 'progressBar');
699                 $("#destinationRectangle").boxCaptionPlugin('init', 'destination');
700                 $("#stillToGoRectangle").boxCaptionPlugin('init', 'still to go');
701                 $('#bottomPanel').bottomPanel('init');
702
703                 var options = {
704                         backgroundColor: "transparent",
705                         mapTypeId: google.maps.MapTypeId.ROADMAP,
706                         mapTypeControl: false,
707                         streetViewControl: false,
708                         zoom: 18
709                 };
710
711                 map = new google.maps.Map(document.getElementById("map_div"), options);
712
713                 startNavigation();
714
715                 $("#placesLibrary").library("setSectionTitle", "PLACES LIBRARY");
716                 $("#placesLibrary").library("init");
717                 $("#placesLibrary").library("hideAlphabet");
718                 $("#placesLibrary").library("setGridBtnDisabled", true);
719                 $("#placesLibrary").library("setSearchBtnDisabled", true);
720
721                 $("#placesButton").on("click", function() {
722                         $("#placesLibrary").library("showPage");
723                 });
724
725                 var tabMenuItems = [ {
726                         text : "DESTINATIONS",
727                         selected : true
728                 } ];
729
730                 var tabMenuModel = {
731                         Tabs : tabMenuItems
732                 };
733
734                 $("#placesLibrary").library("tabMenuTemplateCompile", tabMenuModel);
735                 $("#placesLibrary").library("setContentDelegate", "templates/placesListDelegate.html");
736                 $("#placesLibrary").library("contentTemplateCompile", places, "placesLibraryContentList");
737         });
738 });
739
740 /**
741  * Restarts the navigation with a new destination address taken into account.
742  * @method changeDestinationAddress
743  * @for NavigationGoogle
744  * @param newDestinationAddress {String} a new destination address
745  */
746 function changeDestinationAddress(newDestinationAddress) {
747         "use strict";
748         $("#placesLibrary").library("hidePage");
749
750         destinationAddress = newDestinationAddress;
751
752         origin = null;
753         destination = null;
754         polyline = null;
755         route = null;
756
757         polDistance = 0;
758         remainingDistance = 0;
759         remainingStepDistance = 0;
760         remainingTime = 0;
761         routeDuration = 0;
762         averageSpeed = 0;
763
764         instructions = [];
765         instructionIndex = 0;
766         instructionChanged = true;
767
768         marker.setMap(null);
769         marker = null;
770
771         clearTimeout(timerHandle);
772     timerHandle = null;
773
774     directionRenderer.setMap(null);
775     directionRenderer = null;
776
777     startNavigation();
778 }