source : directions.js

  1. /**
  2. * @ngdoc directive
  3. * @name directions
  4. * @description
  5. * Enable directions on map.
  6. * e.g., origin, destination, draggable, waypoints, etc
  7. *
  8. * Requires: map directive
  9. *
  10. * Restrict To: Element
  11. *
  12. * @attr {String} DirectionsRendererOptions
  13. * [Any DirectionsRendererOptions](https://developers.google.com/maps/documentation/javascript/reference#DirectionsRendererOptions)
  14. * @attr {String} DirectionsRequestOptions
  15. * [Any DirectionsRequest options](https://developers.google.com/maps/documentation/javascript/reference#DirectionsRequest)
  16. * @example
  17. * <map zoom="14" center="37.7699298, -122.4469157">
  18. * <directions
  19. * draggable="true"
  20. * panel="directions-panel"
  21. * travel-mode=""
  22. * waypoints="[{location:'kingston', stopover:true}]"
  23. * origin=""
  24. * destination="">
  25. * </directions>
  26. * </map>
  27. */
  28. /* global document */
  29. (function() {
  30. 'use strict';
  31. var NgMap, $timeout, NavigatorGeolocation;
  32. var requestTimeout, routeRequest;
  33. // Delay for each route render to accumulate all requests into a single one
  34. // This is required for simultaneous origin\waypoints\destination change
  35. // 20ms should be enough to merge all request data
  36. var routeRenderDelay = 20;
  37. var getDirectionsRenderer = function(options, events) {
  38. if (options.panel) {
  39. options.panel = document.getElementById(options.panel) ||
  40. document.querySelector(options.panel);
  41. }
  42. var renderer = new google.maps.DirectionsRenderer(options);
  43. for (var eventName in events) {
  44. google.maps.event.addListener(renderer, eventName, events[eventName]);
  45. }
  46. return renderer;
  47. };
  48. var updateRoute = function(renderer, options) {
  49. var directionsService = new google.maps.DirectionsService();
  50. /* filter out valid keys only for DirectionsRequest object*/
  51. var request = options;
  52. request.travelMode = request.travelMode || 'DRIVING';
  53. var validKeys = [
  54. 'origin', 'destination', 'travelMode', 'transitOptions', 'unitSystem',
  55. 'durationInTraffic', 'waypoints', 'optimizeWaypoints',
  56. 'provideRouteAlternatives', 'avoidHighways', 'avoidTolls', 'region'
  57. ];
  58. if (request) {
  59. for(var key in request) {
  60. if (request.hasOwnProperty(key)) {
  61. (validKeys.indexOf(key) === -1) && (delete request[key]);
  62. }
  63. }
  64. }
  65. if(request.waypoints) {
  66. // Check for acceptable values
  67. if(!Array.isArray(request.waypoints)) {
  68. delete request.waypoints;
  69. }
  70. }
  71. var showDirections = function(request) {
  72. if (requestTimeout && request) {
  73. if (!routeRequest) {
  74. routeRequest = request;
  75. } else {
  76. for (var attr in request) {
  77. if (request.hasOwnProperty(attr)) {
  78. routeRequest[attr] = request[attr];
  79. }
  80. }
  81. }
  82. } else {
  83. requestTimeout = $timeout(function() {
  84. if (!routeRequest) {
  85. routeRequest = request;
  86. }
  87. directionsService.route(routeRequest, function(response, status) {
  88. if (status == google.maps.DirectionsStatus.OK) {
  89. renderer.setDirections(response);
  90. // Unset request for the next call
  91. routeRequest = undefined;
  92. }
  93. });
  94. $timeout.cancel(requestTimeout);
  95. // Unset expired timeout for the next call
  96. requestTimeout = undefined;
  97. }, routeRenderDelay);
  98. }
  99. };
  100. if (request && request.origin && request.destination) {
  101. if (request.origin == 'current-location') {
  102. NavigatorGeolocation.getCurrentPosition().then(function(ll) {
  103. request.origin = new google.maps.LatLng(ll.coords.latitude, ll.coords.longitude);
  104. showDirections(request);
  105. });
  106. } else if (request.destination == 'current-location') {
  107. NavigatorGeolocation.getCurrentPosition().then(function(ll) {
  108. request.destination = new google.maps.LatLng(ll.coords.latitude, ll.coords.longitude);
  109. showDirections(request);
  110. });
  111. } else {
  112. showDirections(request);
  113. }
  114. }
  115. };
  116. var directions = function(
  117. Attr2MapOptions, _$timeout_, _NavigatorGeolocation_, _NgMap_) {
  118. var parser = Attr2MapOptions;
  119. NgMap = _NgMap_;
  120. $timeout = _$timeout_;
  121. NavigatorGeolocation = _NavigatorGeolocation_;
  122. var linkFunc = function(scope, element, attrs, mapController) {
  123. mapController = mapController[0]||mapController[1];
  124. var orgAttrs = parser.orgAttributes(element);
  125. var filtered = parser.filter(attrs);
  126. var options = parser.getOptions(filtered, {scope: scope});
  127. var events = parser.getEvents(scope, filtered);
  128. var attrsToObserve = parser.getAttrsToObserve(orgAttrs);
  129. var attrsToObserve = [];
  130. if (!filtered.noWatcher) {
  131. attrsToObserve = parser.getAttrsToObserve(orgAttrs);
  132. }
  133. var renderer = getDirectionsRenderer(options, events);
  134. mapController.addObject('directionsRenderers', renderer);
  135. attrsToObserve.forEach(function(attrName) {
  136. (function(attrName) {
  137. attrs.$observe(attrName, function(val) {
  138. if (attrName == 'panel') {
  139. $timeout(function(){
  140. var panel =
  141. document.getElementById(val) || document.querySelector(val);
  142. console.log('setting ', attrName, 'with value', panel);
  143. panel && renderer.setPanel(panel);
  144. });
  145. } else if (options[attrName] !== val) { //apply only if changed
  146. var optionValue = parser.toOptionValue(val, {key: attrName});
  147. console.log('setting ', attrName, 'with value', optionValue);
  148. options[attrName] = optionValue;
  149. updateRoute(renderer, options);
  150. }
  151. });
  152. })(attrName);
  153. });
  154. NgMap.getMap().then(function() {
  155. updateRoute(renderer, options);
  156. });
  157. element.bind('$destroy', function() {
  158. mapController.deleteObject('directionsRenderers', renderer);
  159. });
  160. };
  161. return {
  162. restrict: 'E',
  163. require: ['?^map','?^ngMap'],
  164. link: linkFunc
  165. };
  166. }; // var directions
  167. directions.$inject =
  168. ['Attr2MapOptions', '$timeout', 'NavigatorGeolocation', 'NgMap'];
  169. angular.module('ngMap').directive('directions', directions);
  170. })();