location.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. (function ( $ ) {
  2. /**
  3. * Holds google map object and related utility entities.
  4. * @constructor
  5. */
  6. function GMapContext(domElement, options) {
  7. var _map = new google.maps.Map(domElement, options);
  8. var _marker = new google.maps.Marker({
  9. position: new google.maps.LatLng(54.19335, -3.92695),
  10. map: _map,
  11. title: "Drag Me",
  12. draggable: options.draggable
  13. });
  14. return {
  15. map: _map,
  16. marker: _marker,
  17. circle: null,
  18. location: _marker.position,
  19. radius: options.radius,
  20. locationName: options.locationName,
  21. settings: options.settings,
  22. domContainer: domElement,
  23. geodecoder: new google.maps.Geocoder()
  24. }
  25. }
  26. // Utility functions for Google Map Manipulations
  27. var GmUtility = {
  28. /**
  29. * Draw a circle over the the map. Returns circle object.
  30. * Also writes new circle object in gmapContext.
  31. *
  32. * @param center - LatLng of the center of the circle
  33. * @param radius - radius in meters
  34. * @param gmapContext - context
  35. * @param options
  36. */
  37. drawCircle: function(gmapContext, center, radius, options) {
  38. if (gmapContext.circle != null) {
  39. gmapContext.circle.setMap(null);
  40. }
  41. if (radius > 0) {
  42. radius *= 1;
  43. options = $.extend({
  44. strokeColor: "#0000FF",
  45. strokeOpacity: 0.35,
  46. strokeWeight: 2,
  47. fillColor: "#0000FF",
  48. fillOpacity: 0.20
  49. }, options);
  50. options.map = gmapContext.map;
  51. options.radius = radius;
  52. options.center = center;
  53. gmapContext.circle = new google.maps.Circle(options);
  54. return gmapContext.circle;
  55. }
  56. return null;
  57. },
  58. /**
  59. *
  60. * @param gMapContext
  61. * @param location
  62. * @param callback
  63. */
  64. setPosition: function(gMapContext, location, callback) {
  65. gMapContext.location = location;
  66. gMapContext.marker.setPosition(location);
  67. gMapContext.map.panTo(location);
  68. this.drawCircle(gMapContext, location, gMapContext.radius, {});
  69. if (gMapContext.settings.enableReverseGeocode) {
  70. gMapContext.geodecoder.geocode({latLng: gMapContext.location}, function(results, status){
  71. if (status == google.maps.GeocoderStatus.OK && results.length > 0){
  72. gMapContext.locationName = results[0].formatted_address;
  73. }
  74. if (callback) {
  75. callback.call(this, gMapContext);
  76. }
  77. });
  78. } else {
  79. if (callback) {
  80. callback.call(this, gMapContext);
  81. }
  82. }
  83. },
  84. locationFromLatLng: function(lnlg) {
  85. return {latitude: lnlg.lat(), longitude: lnlg.lng()}
  86. }
  87. }
  88. function isPluginApplied(domObj) {
  89. return getContextForElement(domObj) != undefined;
  90. }
  91. function getContextForElement(domObj) {
  92. return $(domObj).data("locationpicker");
  93. }
  94. function updateInputValues(inputBinding, gmapContext){
  95. if (!inputBinding) return;
  96. var currentLocation = GmUtility.locationFromLatLng(gmapContext.location);
  97. if (inputBinding.latitudeInput) {
  98. inputBinding.latitudeInput.val(currentLocation.latitude);
  99. }
  100. if (inputBinding.longitudeInput) {
  101. inputBinding.longitudeInput.val(currentLocation.longitude);
  102. }
  103. if (inputBinding.radiusInput) {
  104. inputBinding.radiusInput.val(gmapContext.radius);
  105. }
  106. if (inputBinding.locationNameInput) {
  107. inputBinding.locationNameInput.val(gmapContext.locationName);
  108. }
  109. }
  110. function setupInputListenersInput(inputBinding, gmapContext) {
  111. if (inputBinding) {
  112. if (inputBinding.radiusInput){
  113. inputBinding.radiusInput.on("change", function() {
  114. gmapContext.radius = $(this).val();
  115. GmUtility.setPosition(gmapContext, gmapContext.location, function(context){
  116. context.settings.onchanged(GmUtility.locationFromLatLng(context.location), context.radius, false);
  117. });
  118. });
  119. }
  120. if (inputBinding.locationNameInput && gmapContext.settings.enableAutocomplete) {
  121. gmapContext.autocomplete = new google.maps.places.Autocomplete(inputBinding.locationNameInput.get(0));
  122. google.maps.event.addListener(gmapContext.autocomplete, 'place_changed', function() {
  123. var place = gmapContext.autocomplete.getPlace();
  124. if (!place.geometry) {
  125. gmapContext.settings.onlocationnotfound(place.name);
  126. return;
  127. }
  128. GmUtility.setPosition(gmapContext, place.geometry.location, function(context) {
  129. updateInputValues(inputBinding, context);
  130. context.settings.onchanged(GmUtility.locationFromLatLng(context.location), context.radius, false);
  131. });
  132. });
  133. }
  134. if (inputBinding.latitudeInput) {
  135. inputBinding.latitudeInput.on("change", function() {
  136. GmUtility.setPosition(gmapContext, new google.maps.LatLng($(this).val(), gmapContext.location.lng()), function(context){
  137. context.settings.onchanged(GmUtility.locationFromLatLng(context.location), context.radius, false);
  138. });
  139. });
  140. }
  141. if (inputBinding.longitudeInput) {
  142. inputBinding.longitudeInput.on("change", function() {
  143. GmUtility.setPosition(gmapContext, new google.maps.LatLng(gmapContext.location.lat(), $(this).val()), function(context){
  144. context.settings.onchanged(GmUtility.locationFromLatLng(context.location), context.radius, false);
  145. });
  146. });
  147. }
  148. }
  149. }
  150. /**
  151. * Initialization:
  152. * $("#myMap").locationpicker(options);
  153. * @param options
  154. * @param params
  155. * @returns {*}
  156. */
  157. $.fn.locationpicker = function( options, params ) {
  158. if (typeof options == 'string') { // Command provided
  159. var _targetDomElement = this.get(0);
  160. // Plug-in is not applied - nothing to do.
  161. if (!isPluginApplied(_targetDomElement)) return;
  162. var gmapContext = getContextForElement(_targetDomElement);
  163. switch (options) {
  164. case "location":
  165. if (params == undefined) { // Getter
  166. var location = GmUtility.locationFromLatLng(gmapContext.location);
  167. location.radius = gmapContext.radius;
  168. location.name = gmapContext.locationName;
  169. return location;
  170. } else { // Setter
  171. if (params.radius) {
  172. gmapContext.radius = params.radius;
  173. }
  174. GmUtility.setPosition(gmapContext, new google.maps.LatLng(params.latitude, params.longitude), function(gmapContext) {
  175. updateInputValues(gmapContext.settings.inputBinding, gmapContext);
  176. });
  177. }
  178. break;
  179. case "subscribe":
  180. /**
  181. * Provides interface for subscribing for GoogleMap events.
  182. * See Google API documentation for details.
  183. * Parameters:
  184. * - event: string, name of the event
  185. * - callback: function, callback function to be invoked
  186. */
  187. if (options == undefined) { // Getter is not available
  188. return null;
  189. } else {
  190. var event = params.event;
  191. var callback = params.callback;
  192. if (!event || ! callback) {
  193. console.error("LocationPicker: Invalid arguments for method \"subscribe\"")
  194. return null;
  195. }
  196. google.maps.event.addListener(gmapContext.map, event, callback);
  197. }
  198. break;
  199. }
  200. return null;
  201. }
  202. return this.each(function() {
  203. var $target = $(this);
  204. // If plug-in hasn't been applied before - initialize, otherwise - skip
  205. if (isPluginApplied(this)) return;
  206. // Plug-in initialization is required
  207. // Defaults
  208. var settings = $.extend({}, $.fn.locationpicker.defaults, options );
  209. // Initialize
  210. var gmapContext = new GMapContext(this, {
  211. zoom: settings.zoom,
  212. center: new google.maps.LatLng(settings.location.latitude, settings.location.longitude),
  213. mapTypeId: google.maps.MapTypeId.ROADMAP,
  214. mapTypeControl: false,
  215. disableDoubleClickZoom: false,
  216. scrollwheel: settings.scrollwheel,
  217. streetViewControl: false,
  218. radius: settings.radius,
  219. locationName: settings.locationName,
  220. settings: settings,
  221. draggable: settings.draggable
  222. });
  223. $target.data("locationpicker", gmapContext);
  224. // Subscribe GMap events
  225. google.maps.event.addListener(gmapContext.marker, "dragend", function(event) {
  226. GmUtility.setPosition(gmapContext, gmapContext.marker.position, function(context){
  227. var currentLocation = GmUtility.locationFromLatLng(gmapContext.location);
  228. context.settings.onchanged(currentLocation, context.radius, true);
  229. updateInputValues(gmapContext.settings.inputBinding, gmapContext);
  230. });
  231. });
  232. GmUtility.setPosition(gmapContext, new google.maps.LatLng(settings.location.latitude, settings.location.longitude), function(context){
  233. updateInputValues(settings.inputBinding, gmapContext);
  234. context.settings.oninitialized($target);
  235. });
  236. // Set up input bindings if needed
  237. setupInputListenersInput(settings.inputBinding, gmapContext);
  238. });
  239. };
  240. $.fn.locationpicker.defaults = {
  241. location: {latitude: 40.7324319, longitude: -73.82480799999996},
  242. locationName: "",
  243. radius: 500,
  244. zoom: 15,
  245. scrollwheel: true,
  246. inputBinding: {
  247. latitudeInput: null,
  248. longitudeInput: null,
  249. radiusInput: null,
  250. locationNameInput: null
  251. },
  252. enableAutocomplete: false,
  253. enableReverseGeocode: true,
  254. draggable: true,
  255. onchanged: function(currentLocation, radius, isMarkerDropped) {},
  256. onlocationnotfound: function(locationName) {},
  257. oninitialized: function (component) {}
  258. }
  259. }( jQuery ));