source : info-window.js

  1. /**
  2. * @ngdoc directive
  3. * @name info-window
  4. * @param Attr2MapOptions {service}
  5. * convert html attribute to Google map api options
  6. * @param $compile {service} $compile service
  7. * @description
  8. * Defines infoWindow and provides compile method
  9. *
  10. * Requires: map directive
  11. *
  12. * Restrict To: Element
  13. *
  14. * NOTE: this directive should **NOT** be used with `ng-repeat`
  15. * because InfoWindow itself is a template, and a template must be
  16. * reused by each marker, thus, should not be redefined repeatedly
  17. * by `ng-repeat`.
  18. *
  19. * @attr {Boolean} visible
  20. * Indicates to show it when map is initialized
  21. * @attr {Boolean} visible-on-marker
  22. * Indicates to show it on a marker when map is initialized
  23. * @attr {Expression} geo-callback
  24. * if position is an address, the expression is will be performed
  25. * when geo-lookup is successful. e.g., geo-callback="showDetail()"
  26. * @attr {String} <InfoWindowOption> Any InfoWindow options,
  27. * https://developers.google.com/maps/documentation/javascript/reference?csw=1#InfoWindowOptions
  28. * @attr {String} <InfoWindowEvent> Any InfoWindow events,
  29. * https://developers.google.com/maps/documentation/javascript/reference
  30. * @example
  31. * Usage:
  32. * <map MAP_ATTRIBUTES>
  33. * <info-window id="foo" ANY_OPTIONS ANY_EVENTS"></info-window>
  34. * </map>
  35. *
  36. * Example:
  37. * <map center="41.850033,-87.6500523" zoom="3">
  38. * <info-window id="1" position="41.850033,-87.6500523" >
  39. * <div ng-non-bindable>
  40. * Chicago, IL<br/>
  41. * LatLng: , , <br/>
  42. * World Coordinate: , , <br/>
  43. * Pixel Coordinate: , , <br/>
  44. * Tile Coordinate: , at Zoom Level
  45. * </div>
  46. * </info-window>
  47. * </map>
  48. */
  49. /* global google */
  50. (function() {
  51. 'use strict';
  52. var infoWindow = function(Attr2MapOptions, $compile, $q, $templateRequest, $timeout, $parse, NgMap) {
  53. var parser = Attr2MapOptions;
  54. var getInfoWindow = function(options, events, element) {
  55. var infoWindow;
  56. /**
  57. * set options
  58. */
  59. if (options.position && !(options.position instanceof google.maps.LatLng)) {
  60. delete options.position;
  61. }
  62. infoWindow = new google.maps.InfoWindow(options);
  63. /**
  64. * set events
  65. */
  66. for (var eventName in events) {
  67. if (eventName) {
  68. google.maps.event.addListener(infoWindow, eventName, events[eventName]);
  69. }
  70. }
  71. /**
  72. * set template and template-related functions
  73. * it must have a container element with ng-non-bindable
  74. */
  75. var templatePromise = $q(function(resolve) {
  76. if (angular.isString(element)) {
  77. $templateRequest(element).then(function (requestedTemplate) {
  78. resolve(angular.element(requestedTemplate).wrap('<div>').parent());
  79. }, function(message) {
  80. throw "info-window template request failed: " + message;
  81. });
  82. }
  83. else {
  84. resolve(element);
  85. }
  86. }).then(function(resolvedTemplate) {
  87. var template = resolvedTemplate.html().trim();
  88. if (angular.element(template).length != 1) {
  89. throw "info-window working as a template must have a container";
  90. }
  91. infoWindow.__template = template.replace(/\s?ng-non-bindable[='"]+/,"");
  92. });
  93. infoWindow.__open = function(map, scope, anchor) {
  94. templatePromise.then(function() {
  95. $timeout(function() {
  96. anchor && (scope.anchor = anchor);
  97. var el = $compile(infoWindow.__template)(scope);
  98. infoWindow.setContent(el[0]);
  99. scope.$apply();
  100. if (anchor && anchor.getPosition) {
  101. infoWindow.open(map, anchor);
  102. } else if (anchor && anchor instanceof google.maps.LatLng) {
  103. infoWindow.open(map);
  104. infoWindow.setPosition(anchor);
  105. } else {
  106. infoWindow.open(map);
  107. }
  108. $timeout(function() { // to avoid racing condition
  109. var infoWindowContainerEl = infoWindow.content.parentElement.parentElement.parentElement;
  110. infoWindowContainerEl.className = "ng-map-info-window";
  111. });
  112. });
  113. });
  114. };
  115. return infoWindow;
  116. };
  117. var linkFunc = function(scope, element, attrs, mapController) {
  118. mapController = mapController[0]||mapController[1];
  119. element.css('display','none');
  120. var orgAttrs = parser.orgAttributes(element);
  121. var filtered = parser.filter(attrs);
  122. var options = parser.getOptions(filtered, {scope: scope});
  123. var events = parser.getEvents(scope, filtered);
  124. var infoWindow = getInfoWindow(options, events, options.template || element);
  125. var address;
  126. if (options.position && !(options.position instanceof google.maps.LatLng)) {
  127. address = options.position;
  128. }
  129. if (address) {
  130. NgMap.getGeoLocation(address).then(function(latlng) {
  131. infoWindow.setPosition(latlng);
  132. infoWindow.__open(mapController.map, scope, latlng);
  133. var geoCallback = attrs.geoCallback;
  134. geoCallback && $parse(geoCallback)(scope);
  135. });
  136. }
  137. mapController.addObject('infoWindows', infoWindow);
  138. mapController.observeAttrSetObj(orgAttrs, attrs, infoWindow);
  139. mapController.showInfoWindow =
  140. mapController.map.showInfoWindow = mapController.showInfoWindow ||
  141. function(p1, p2, p3) { //event, id, marker
  142. var id = typeof p1 == 'string' ? p1 : p2;
  143. var marker = typeof p1 == 'string' ? p2 : p3;
  144. if (typeof marker == 'string') {
  145. //Check if markers if defined to avoid odd 'undefined' errors
  146. if (
  147. typeof mapController.map.markers != "undefined"
  148. && typeof mapController.map.markers[marker] != "undefined") {
  149. marker = mapController.map.markers[marker];
  150. } else if (
  151. //additionally check if that marker is a custom marker
  152. typeof mapController.map.customMarkers !== "undefined"
  153. && typeof mapController.map.customMarkers[marker] !== "undefined") {
  154. marker = mapController.map.customMarkers[marker];
  155. } else {
  156. //Better error output if marker with that id is not defined
  157. throw new Error("Cant open info window for id " + marker + ". Marker or CustomMarker is not defined")
  158. }
  159. }
  160. var infoWindow = mapController.map.infoWindows[id];
  161. var anchor = marker ? marker : (this.getPosition ? this : null);
  162. infoWindow.__open(mapController.map, scope, anchor);
  163. if(mapController.singleInfoWindow) {
  164. if(mapController.lastInfoWindow) {
  165. scope.hideInfoWindow(mapController.lastInfoWindow);
  166. }
  167. mapController.lastInfoWindow = id;
  168. }
  169. };
  170. mapController.hideInfoWindow =
  171. mapController.map.hideInfoWindow = mapController.hideInfoWindow ||
  172. function(p1, p2) {
  173. var id = typeof p1 == 'string' ? p1 : p2;
  174. var infoWindow = mapController.map.infoWindows[id];
  175. infoWindow.close();
  176. };
  177. //TODO DEPRECATED
  178. scope.showInfoWindow = mapController.map.showInfoWindow;
  179. scope.hideInfoWindow = mapController.map.hideInfoWindow;
  180. var map = infoWindow.mapId ? {id:infoWindow.mapId} : 0;
  181. NgMap.getMap(map).then(function(map) {
  182. infoWindow.visible && infoWindow.__open(map, scope);
  183. if (infoWindow.visibleOnMarker) {
  184. var markerId = infoWindow.visibleOnMarker;
  185. infoWindow.__open(map, scope, map.markers[markerId]);
  186. }
  187. });
  188. }; //link
  189. return {
  190. restrict: 'E',
  191. require: ['?^map','?^ngMap'],
  192. link: linkFunc
  193. };
  194. }; // infoWindow
  195. infoWindow.$inject =
  196. ['Attr2MapOptions', '$compile', '$q', '$templateRequest', '$timeout', '$parse', 'NgMap'];
  197. angular.module('ngMap').directive('infoWindow', infoWindow);
  198. })();