gmaps.js 64 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409
  1. "use strict";
  2. (function(root, factory) {
  3. if(typeof exports === 'object') {
  4. module.exports = factory();
  5. }
  6. else if(typeof define === 'function' && define.amd) {
  7. define(['jquery', 'googlemaps!'], factory);
  8. }
  9. else {
  10. root.GMaps = factory();
  11. }
  12. }(this, function() {
  13. /*!
  14. * GMaps.js v0.4.24
  15. * http://hpneo.github.com/gmaps/
  16. *
  17. * Copyright 2016, Gustavo Leon
  18. * Released under the MIT License.
  19. */
  20. var extend_object = function(obj, new_obj) {
  21. var name;
  22. if (obj === new_obj) {
  23. return obj;
  24. }
  25. for (name in new_obj) {
  26. if (new_obj[name] !== undefined) {
  27. obj[name] = new_obj[name];
  28. }
  29. }
  30. return obj;
  31. };
  32. var replace_object = function(obj, replace) {
  33. var name;
  34. if (obj === replace) {
  35. return obj;
  36. }
  37. for (name in replace) {
  38. if (obj[name] != undefined) {
  39. obj[name] = replace[name];
  40. }
  41. }
  42. return obj;
  43. };
  44. var array_map = function(array, callback) {
  45. var original_callback_params = Array.prototype.slice.call(arguments, 2),
  46. array_return = [],
  47. array_length = array.length,
  48. i;
  49. if (Array.prototype.map && array.map === Array.prototype.map) {
  50. array_return = Array.prototype.map.call(array, function(item) {
  51. var callback_params = original_callback_params.slice(0);
  52. callback_params.splice(0, 0, item);
  53. return callback.apply(this, callback_params);
  54. });
  55. }
  56. else {
  57. for (i = 0; i < array_length; i++) {
  58. callback_params = original_callback_params;
  59. callback_params.splice(0, 0, array[i]);
  60. array_return.push(callback.apply(this, callback_params));
  61. }
  62. }
  63. return array_return;
  64. };
  65. var array_flat = function(array) {
  66. var new_array = [],
  67. i;
  68. for (i = 0; i < array.length; i++) {
  69. new_array = new_array.concat(array[i]);
  70. }
  71. return new_array;
  72. };
  73. var coordsToLatLngs = function(coords, useGeoJSON) {
  74. var first_coord = coords[0],
  75. second_coord = coords[1];
  76. if (useGeoJSON) {
  77. first_coord = coords[1];
  78. second_coord = coords[0];
  79. }
  80. return new google.maps.LatLng(first_coord, second_coord);
  81. };
  82. var arrayToLatLng = function(coords, useGeoJSON) {
  83. var i;
  84. for (i = 0; i < coords.length; i++) {
  85. if (!(coords[i] instanceof google.maps.LatLng)) {
  86. if (coords[i].length > 0 && typeof(coords[i][0]) === "object") {
  87. coords[i] = arrayToLatLng(coords[i], useGeoJSON);
  88. }
  89. else {
  90. coords[i] = coordsToLatLngs(coords[i], useGeoJSON);
  91. }
  92. }
  93. }
  94. return coords;
  95. };
  96. var getElementsByClassName = function (class_name, context) {
  97. var element,
  98. _class = class_name.replace('.', '');
  99. if ('jQuery' in this && context) {
  100. element = $("." + _class, context)[0];
  101. } else {
  102. element = document.getElementsByClassName(_class)[0];
  103. }
  104. return element;
  105. };
  106. var getElementById = function(id, context) {
  107. var element,
  108. id = id.replace('#', '');
  109. if ('jQuery' in window && context) {
  110. element = $('#' + id, context)[0];
  111. } else {
  112. element = document.getElementById(id);
  113. };
  114. return element;
  115. };
  116. var findAbsolutePosition = function(obj) {
  117. var curleft = 0,
  118. curtop = 0;
  119. if (obj.offsetParent) {
  120. do {
  121. curleft += obj.offsetLeft;
  122. curtop += obj.offsetTop;
  123. } while (obj = obj.offsetParent);
  124. }
  125. return [curleft, curtop];
  126. };
  127. var GMaps = (function(global) {
  128. "use strict";
  129. var doc = document;
  130. /**
  131. * Creates a new GMaps instance, including a Google Maps map.
  132. * @class GMaps
  133. * @constructs
  134. * @param {object} options - `options` accepts all the [MapOptions](https://developers.google.com/maps/documentation/javascript/reference#MapOptions) and [events](https://developers.google.com/maps/documentation/javascript/reference#Map) listed in the Google Maps API. Also accepts:
  135. * * `lat` (number): Latitude of the map's center
  136. * * `lng` (number): Longitude of the map's center
  137. * * `el` (string or HTMLElement): container where the map will be rendered
  138. * * `markerClusterer` (function): A function to create a marker cluster. You can use MarkerClusterer or MarkerClustererPlus.
  139. */
  140. var GMaps = function(options) {
  141. if (!(typeof window.google === 'object' && window.google.maps)) {
  142. if (typeof window.console === 'object' && window.console.error) {
  143. console.error('Google Maps API is required. Please register the following JavaScript library https://maps.googleapis.com/maps/api/js.');
  144. }
  145. return function() {};
  146. }
  147. if (!this) return new GMaps(options);
  148. options.zoom = options.zoom || 15;
  149. options.mapType = options.mapType || 'roadmap';
  150. var valueOrDefault = function(value, defaultValue) {
  151. return value === undefined ? defaultValue : value;
  152. };
  153. var self = this,
  154. i,
  155. events_that_hide_context_menu = [
  156. 'bounds_changed', 'center_changed', 'click', 'dblclick', 'drag',
  157. 'dragend', 'dragstart', 'idle', 'maptypeid_changed', 'projection_changed',
  158. 'resize', 'tilesloaded', 'zoom_changed'
  159. ],
  160. events_that_doesnt_hide_context_menu = ['mousemove', 'mouseout', 'mouseover'],
  161. options_to_be_deleted = ['el', 'lat', 'lng', 'mapType', 'width', 'height', 'markerClusterer', 'enableNewStyle'],
  162. identifier = options.el || options.div,
  163. markerClustererFunction = options.markerClusterer,
  164. mapType = google.maps.MapTypeId[options.mapType.toUpperCase()],
  165. map_center = new google.maps.LatLng(options.lat, options.lng),
  166. zoomControl = valueOrDefault(options.zoomControl, true),
  167. zoomControlOpt = options.zoomControlOpt || {
  168. style: 'DEFAULT',
  169. position: 'TOP_LEFT'
  170. },
  171. zoomControlStyle = zoomControlOpt.style || 'DEFAULT',
  172. zoomControlPosition = zoomControlOpt.position || 'TOP_LEFT',
  173. panControl = valueOrDefault(options.panControl, true),
  174. mapTypeControl = valueOrDefault(options.mapTypeControl, true),
  175. scaleControl = valueOrDefault(options.scaleControl, true),
  176. streetViewControl = valueOrDefault(options.streetViewControl, true),
  177. overviewMapControl = valueOrDefault(overviewMapControl, true),
  178. map_options = {},
  179. map_base_options = {
  180. zoom: this.zoom,
  181. center: map_center,
  182. mapTypeId: mapType
  183. },
  184. map_controls_options = {
  185. panControl: panControl,
  186. zoomControl: zoomControl,
  187. zoomControlOptions: {
  188. style: google.maps.ZoomControlStyle[zoomControlStyle],
  189. position: google.maps.ControlPosition[zoomControlPosition]
  190. },
  191. mapTypeControl: mapTypeControl,
  192. scaleControl: scaleControl,
  193. streetViewControl: streetViewControl,
  194. overviewMapControl: overviewMapControl
  195. };
  196. if (typeof(options.el) === 'string' || typeof(options.div) === 'string') {
  197. if (identifier.indexOf("#") > -1) {
  198. /**
  199. * Container element
  200. *
  201. * @type {HTMLElement}
  202. */
  203. this.el = getElementById(identifier, options.context);
  204. } else {
  205. this.el = getElementsByClassName.apply(this, [identifier, options.context]);
  206. }
  207. } else {
  208. this.el = identifier;
  209. }
  210. if (typeof(this.el) === 'undefined' || this.el === null) {
  211. throw 'No element defined.';
  212. }
  213. window.context_menu = window.context_menu || {};
  214. window.context_menu[self.el.id] = {};
  215. /**
  216. * Collection of custom controls in the map UI
  217. *
  218. * @type {array}
  219. */
  220. this.controls = [];
  221. /**
  222. * Collection of map's overlays
  223. *
  224. * @type {array}
  225. */
  226. this.overlays = [];
  227. /**
  228. * Collection of KML/GeoRSS and FusionTable layers
  229. *
  230. * @type {array}
  231. */
  232. this.layers = [];
  233. /**
  234. * Collection of data layers (See {@link GMaps#addLayer})
  235. *
  236. * @type {object}
  237. */
  238. this.singleLayers = {};
  239. /**
  240. * Collection of map's markers
  241. *
  242. * @type {array}
  243. */
  244. this.markers = [];
  245. /**
  246. * Collection of map's lines
  247. *
  248. * @type {array}
  249. */
  250. this.polylines = [];
  251. /**
  252. * Collection of map's routes requested by {@link GMaps#getRoutes}, {@link GMaps#renderRoute}, {@link GMaps#drawRoute}, {@link GMaps#travelRoute} or {@link GMaps#drawSteppedRoute}
  253. *
  254. * @type {array}
  255. */
  256. this.routes = [];
  257. /**
  258. * Collection of map's polygons
  259. *
  260. * @type {array}
  261. */
  262. this.polygons = [];
  263. this.infoWindow = null;
  264. this.overlay_el = null;
  265. /**
  266. * Current map's zoom
  267. *
  268. * @type {number}
  269. */
  270. this.zoom = options.zoom;
  271. this.registered_events = {};
  272. this.el.style.width = options.width || this.el.scrollWidth || this.el.offsetWidth;
  273. this.el.style.height = options.height || this.el.scrollHeight || this.el.offsetHeight;
  274. google.maps.visualRefresh = options.enableNewStyle;
  275. for (i = 0; i < options_to_be_deleted.length; i++) {
  276. delete options[options_to_be_deleted[i]];
  277. }
  278. if(options.disableDefaultUI != true) {
  279. map_base_options = extend_object(map_base_options, map_controls_options);
  280. }
  281. map_options = extend_object(map_base_options, options);
  282. for (i = 0; i < events_that_hide_context_menu.length; i++) {
  283. delete map_options[events_that_hide_context_menu[i]];
  284. }
  285. for (i = 0; i < events_that_doesnt_hide_context_menu.length; i++) {
  286. delete map_options[events_that_doesnt_hide_context_menu[i]];
  287. }
  288. /**
  289. * Google Maps map instance
  290. *
  291. * @type {google.maps.Map}
  292. */
  293. this.map = new google.maps.Map(this.el, map_options);
  294. if (markerClustererFunction) {
  295. /**
  296. * Marker Clusterer instance
  297. *
  298. * @type {object}
  299. */
  300. this.markerClusterer = markerClustererFunction.apply(this, [this.map]);
  301. }
  302. var buildContextMenuHTML = function(control, e) {
  303. var html = '',
  304. options = window.context_menu[self.el.id][control];
  305. for (var i in options){
  306. if (options.hasOwnProperty(i)) {
  307. var option = options[i];
  308. html += '<li><a id="' + control + '_' + i + '" href="#">' + option.title + '</a></li>';
  309. }
  310. }
  311. if (!getElementById('gmaps_context_menu')) return;
  312. var context_menu_element = getElementById('gmaps_context_menu');
  313. context_menu_element.innerHTML = html;
  314. var context_menu_items = context_menu_element.getElementsByTagName('a'),
  315. context_menu_items_count = context_menu_items.length,
  316. i;
  317. for (i = 0; i < context_menu_items_count; i++) {
  318. var context_menu_item = context_menu_items[i];
  319. var assign_menu_item_action = function(ev){
  320. ev.preventDefault();
  321. options[this.id.replace(control + '_', '')].action.apply(self, [e]);
  322. self.hideContextMenu();
  323. };
  324. google.maps.event.clearListeners(context_menu_item, 'click');
  325. google.maps.event.addDomListenerOnce(context_menu_item, 'click', assign_menu_item_action, false);
  326. }
  327. var position = findAbsolutePosition.apply(this, [self.el]),
  328. left = position[0] + e.pixel.x - 15,
  329. top = position[1] + e.pixel.y- 15;
  330. context_menu_element.style.left = left + "px";
  331. context_menu_element.style.top = top + "px";
  332. // context_menu_element.style.display = 'block';
  333. };
  334. this.buildContextMenu = function(control, e) {
  335. if (control === 'marker') {
  336. e.pixel = {};
  337. var overlay = new google.maps.OverlayView();
  338. overlay.setMap(self.map);
  339. overlay.draw = function() {
  340. var projection = overlay.getProjection(),
  341. position = e.marker.getPosition();
  342. e.pixel = projection.fromLatLngToContainerPixel(position);
  343. buildContextMenuHTML(control, e);
  344. };
  345. }
  346. else {
  347. buildContextMenuHTML(control, e);
  348. }
  349. var context_menu_element = getElementById('gmaps_context_menu');
  350. setTimeout(function() {
  351. context_menu_element.style.display = 'block';
  352. }, 0);
  353. };
  354. /**
  355. * Add a context menu for a map or a marker.
  356. *
  357. * @param {object} options - The `options` object should contain:
  358. * * `control` (string): Kind of control the context menu will be attached. Can be "map" or "marker".
  359. * * `options` (array): A collection of context menu items:
  360. * * `title` (string): Item's title shown in the context menu.
  361. * * `name` (string): Item's identifier.
  362. * * `action` (function): Function triggered after selecting the context menu item.
  363. */
  364. this.setContextMenu = function(options) {
  365. window.context_menu[self.el.id][options.control] = {};
  366. var i,
  367. ul = doc.createElement('ul');
  368. for (i in options.options) {
  369. if (options.options.hasOwnProperty(i)) {
  370. var option = options.options[i];
  371. window.context_menu[self.el.id][options.control][option.name] = {
  372. title: option.title,
  373. action: option.action
  374. };
  375. }
  376. }
  377. ul.id = 'gmaps_context_menu';
  378. ul.style.display = 'none';
  379. ul.style.position = 'absolute';
  380. ul.style.minWidth = '100px';
  381. ul.style.background = 'white';
  382. ul.style.listStyle = 'none';
  383. ul.style.padding = '8px';
  384. ul.style.boxShadow = '2px 2px 6px #ccc';
  385. if (!getElementById('gmaps_context_menu')) {
  386. doc.body.appendChild(ul);
  387. }
  388. var context_menu_element = getElementById('gmaps_context_menu');
  389. google.maps.event.addDomListener(context_menu_element, 'mouseout', function(ev) {
  390. if (!ev.relatedTarget || !this.contains(ev.relatedTarget)) {
  391. window.setTimeout(function(){
  392. context_menu_element.style.display = 'none';
  393. }, 400);
  394. }
  395. }, false);
  396. };
  397. /**
  398. * Hide the current context menu
  399. */
  400. this.hideContextMenu = function() {
  401. var context_menu_element = getElementById('gmaps_context_menu');
  402. if (context_menu_element) {
  403. context_menu_element.style.display = 'none';
  404. }
  405. };
  406. var setupListener = function(object, name) {
  407. google.maps.event.addListener(object, name, function(e){
  408. if (e == undefined) {
  409. e = this;
  410. }
  411. options[name].apply(this, [e]);
  412. self.hideContextMenu();
  413. });
  414. };
  415. //google.maps.event.addListener(this.map, 'idle', this.hideContextMenu);
  416. google.maps.event.addListener(this.map, 'zoom_changed', this.hideContextMenu);
  417. for (var ev = 0; ev < events_that_hide_context_menu.length; ev++) {
  418. var name = events_that_hide_context_menu[ev];
  419. if (name in options) {
  420. setupListener(this.map, name);
  421. }
  422. }
  423. for (var ev = 0; ev < events_that_doesnt_hide_context_menu.length; ev++) {
  424. var name = events_that_doesnt_hide_context_menu[ev];
  425. if (name in options) {
  426. setupListener(this.map, name);
  427. }
  428. }
  429. google.maps.event.addListener(this.map, 'rightclick', function(e) {
  430. if (options.rightclick) {
  431. options.rightclick.apply(this, [e]);
  432. }
  433. if(window.context_menu[self.el.id]['map'] != undefined) {
  434. self.buildContextMenu('map', e);
  435. }
  436. });
  437. /**
  438. * Trigger a `resize` event, useful if you need to repaint the current map (for changes in the viewport or display / hide actions).
  439. */
  440. this.refresh = function() {
  441. google.maps.event.trigger(this.map, 'resize');
  442. };
  443. /**
  444. * Adjust the map zoom to include all the markers added in the map.
  445. */
  446. this.fitZoom = function() {
  447. var latLngs = [],
  448. markers_length = this.markers.length,
  449. i;
  450. for (i = 0; i < markers_length; i++) {
  451. if(typeof(this.markers[i].visible) === 'boolean' && this.markers[i].visible) {
  452. latLngs.push(this.markers[i].getPosition());
  453. }
  454. }
  455. this.fitLatLngBounds(latLngs);
  456. };
  457. /**
  458. * Adjust the map zoom to include all the coordinates in the `latLngs` array.
  459. *
  460. * @param {array} latLngs - Collection of `google.maps.LatLng` objects.
  461. */
  462. this.fitLatLngBounds = function(latLngs) {
  463. var total = latLngs.length,
  464. bounds = new google.maps.LatLngBounds(),
  465. i;
  466. for(i = 0; i < total; i++) {
  467. bounds.extend(latLngs[i]);
  468. }
  469. this.map.fitBounds(bounds);
  470. };
  471. /**
  472. * Center the map using the `lat` and `lng` coordinates.
  473. *
  474. * @param {number} lat - Latitude of the coordinate.
  475. * @param {number} lng - Longitude of the coordinate.
  476. * @param {function} [callback] - Callback that will be executed after the map is centered.
  477. */
  478. this.setCenter = function(lat, lng, callback) {
  479. this.map.panTo(new google.maps.LatLng(lat, lng));
  480. if (callback) {
  481. callback();
  482. }
  483. };
  484. /**
  485. * Return the HTML element container of the map.
  486. *
  487. * @returns {HTMLElement} the element container.
  488. */
  489. this.getElement = function() {
  490. return this.el;
  491. };
  492. /**
  493. * Increase the map's zoom.
  494. *
  495. * @param {number} [magnitude] - The number of times the map will be zoomed in.
  496. */
  497. this.zoomIn = function(value) {
  498. value = value || 1;
  499. this.zoom = this.map.getZoom() + value;
  500. this.map.setZoom(this.zoom);
  501. };
  502. /**
  503. * Decrease the map's zoom.
  504. *
  505. * @param {number} [magnitude] - The number of times the map will be zoomed out.
  506. */
  507. this.zoomOut = function(value) {
  508. value = value || 1;
  509. this.zoom = this.map.getZoom() - value;
  510. this.map.setZoom(this.zoom);
  511. };
  512. var native_methods = [],
  513. method;
  514. for (method in this.map) {
  515. if (typeof(this.map[method]) == 'function' && !this[method]) {
  516. native_methods.push(method);
  517. }
  518. }
  519. for (i = 0; i < native_methods.length; i++) {
  520. (function(gmaps, scope, method_name) {
  521. gmaps[method_name] = function(){
  522. return scope[method_name].apply(scope, arguments);
  523. };
  524. })(this, this.map, native_methods[i]);
  525. }
  526. };
  527. return GMaps;
  528. })(this);
  529. GMaps.prototype.createControl = function(options) {
  530. var control = document.createElement('div');
  531. control.style.cursor = 'pointer';
  532. if (options.disableDefaultStyles !== true) {
  533. control.style.fontFamily = 'Roboto, Arial, sans-serif';
  534. control.style.fontSize = '11px';
  535. control.style.boxShadow = 'rgba(0, 0, 0, 0.298039) 0px 1px 4px -1px';
  536. }
  537. for (var option in options.style) {
  538. control.style[option] = options.style[option];
  539. }
  540. if (options.id) {
  541. control.id = options.id;
  542. }
  543. if (options.title) {
  544. control.title = options.title;
  545. }
  546. if (options.classes) {
  547. control.className = options.classes;
  548. }
  549. if (options.content) {
  550. if (typeof options.content === 'string') {
  551. control.innerHTML = options.content;
  552. }
  553. else if (options.content instanceof HTMLElement) {
  554. control.appendChild(options.content);
  555. }
  556. }
  557. if (options.position) {
  558. control.position = google.maps.ControlPosition[options.position.toUpperCase()];
  559. }
  560. for (var ev in options.events) {
  561. (function(object, name) {
  562. google.maps.event.addDomListener(object, name, function(){
  563. options.events[name].apply(this, [this]);
  564. });
  565. })(control, ev);
  566. }
  567. control.index = 1;
  568. return control;
  569. };
  570. /**
  571. * Add a custom control to the map UI.
  572. *
  573. * @param {object} options - The `options` object should contain:
  574. * * `style` (object): The keys and values of this object should be valid CSS properties and values.
  575. * * `id` (string): The HTML id for the custom control.
  576. * * `classes` (string): A string containing all the HTML classes for the custom control.
  577. * * `content` (string or HTML element): The content of the custom control.
  578. * * `position` (string): Any valid [`google.maps.ControlPosition`](https://developers.google.com/maps/documentation/javascript/controls#ControlPositioning) value, in lower or upper case.
  579. * * `events` (object): The keys of this object should be valid DOM events. The values should be functions.
  580. * * `disableDefaultStyles` (boolean): If false, removes the default styles for the controls like font (family and size), and box shadow.
  581. * @returns {HTMLElement}
  582. */
  583. GMaps.prototype.addControl = function(options) {
  584. var control = this.createControl(options);
  585. this.controls.push(control);
  586. this.map.controls[control.position].push(control);
  587. return control;
  588. };
  589. /**
  590. * Remove a control from the map. `control` should be a control returned by `addControl()`.
  591. *
  592. * @param {HTMLElement} control - One of the controls returned by `addControl()`.
  593. * @returns {HTMLElement} the removed control.
  594. */
  595. GMaps.prototype.removeControl = function(control) {
  596. var position = null,
  597. i;
  598. for (i = 0; i < this.controls.length; i++) {
  599. if (this.controls[i] == control) {
  600. position = this.controls[i].position;
  601. this.controls.splice(i, 1);
  602. }
  603. }
  604. if (position) {
  605. for (i = 0; i < this.map.controls.length; i++) {
  606. var controlsForPosition = this.map.controls[control.position];
  607. if (controlsForPosition.getAt(i) == control) {
  608. controlsForPosition.removeAt(i);
  609. break;
  610. }
  611. }
  612. }
  613. return control;
  614. };
  615. GMaps.prototype.createMarker = function(options) {
  616. if (options.lat == undefined && options.lng == undefined && options.position == undefined) {
  617. throw 'No latitude or longitude defined.';
  618. }
  619. var self = this,
  620. details = options.details,
  621. fences = options.fences,
  622. outside = options.outside,
  623. base_options = {
  624. position: new google.maps.LatLng(options.lat, options.lng),
  625. map: null
  626. },
  627. marker_options = extend_object(base_options, options);
  628. delete marker_options.lat;
  629. delete marker_options.lng;
  630. delete marker_options.fences;
  631. delete marker_options.outside;
  632. var marker = new google.maps.Marker(marker_options);
  633. marker.fences = fences;
  634. if (options.infoWindow) {
  635. marker.infoWindow = new google.maps.InfoWindow(options.infoWindow);
  636. var info_window_events = ['closeclick', 'content_changed', 'domready', 'position_changed', 'zindex_changed'];
  637. for (var ev = 0; ev < info_window_events.length; ev++) {
  638. (function(object, name) {
  639. if (options.infoWindow[name]) {
  640. google.maps.event.addListener(object, name, function(e){
  641. options.infoWindow[name].apply(this, [e]);
  642. });
  643. }
  644. })(marker.infoWindow, info_window_events[ev]);
  645. }
  646. }
  647. var marker_events = ['animation_changed', 'clickable_changed', 'cursor_changed', 'draggable_changed', 'flat_changed', 'icon_changed', 'position_changed', 'shadow_changed', 'shape_changed', 'title_changed', 'visible_changed', 'zindex_changed'];
  648. var marker_events_with_mouse = ['dblclick', 'drag', 'dragend', 'dragstart', 'mousedown', 'mouseout', 'mouseover', 'mouseup'];
  649. for (var ev = 0; ev < marker_events.length; ev++) {
  650. (function(object, name) {
  651. if (options[name]) {
  652. google.maps.event.addListener(object, name, function(){
  653. options[name].apply(this, [this]);
  654. });
  655. }
  656. })(marker, marker_events[ev]);
  657. }
  658. for (var ev = 0; ev < marker_events_with_mouse.length; ev++) {
  659. (function(map, object, name) {
  660. if (options[name]) {
  661. google.maps.event.addListener(object, name, function(me){
  662. if(!me.pixel){
  663. me.pixel = map.getProjection().fromLatLngToPoint(me.latLng)
  664. }
  665. options[name].apply(this, [me]);
  666. });
  667. }
  668. })(this.map, marker, marker_events_with_mouse[ev]);
  669. }
  670. google.maps.event.addListener(marker, 'click', function() {
  671. this.details = details;
  672. if (options.click) {
  673. options.click.apply(this, [this]);
  674. }
  675. if (marker.infoWindow) {
  676. self.hideInfoWindows();
  677. marker.infoWindow.open(self.map, marker);
  678. }
  679. });
  680. google.maps.event.addListener(marker, 'rightclick', function(e) {
  681. e.marker = this;
  682. if (options.rightclick) {
  683. options.rightclick.apply(this, [e]);
  684. }
  685. if (window.context_menu[self.el.id]['marker'] != undefined) {
  686. self.buildContextMenu('marker', e);
  687. }
  688. });
  689. if (marker.fences) {
  690. google.maps.event.addListener(marker, 'dragend', function() {
  691. self.checkMarkerGeofence(marker, function(m, f) {
  692. outside(m, f);
  693. });
  694. });
  695. }
  696. return marker;
  697. };
  698. GMaps.prototype.addMarker = function(options) {
  699. var marker;
  700. if(options.hasOwnProperty('gm_accessors_')) {
  701. // Native google.maps.Marker object
  702. marker = options;
  703. }
  704. else {
  705. if ((options.hasOwnProperty('lat') && options.hasOwnProperty('lng')) || options.position) {
  706. marker = this.createMarker(options);
  707. }
  708. else {
  709. throw 'No latitude or longitude defined.';
  710. }
  711. }
  712. marker.setMap(this.map);
  713. if(this.markerClusterer) {
  714. this.markerClusterer.addMarker(marker);
  715. }
  716. this.markers.push(marker);
  717. GMaps.fire('marker_added', marker, this);
  718. return marker;
  719. };
  720. GMaps.prototype.addMarkers = function(array) {
  721. for (var i = 0, marker; marker=array[i]; i++) {
  722. this.addMarker(marker);
  723. }
  724. return this.markers;
  725. };
  726. GMaps.prototype.hideInfoWindows = function() {
  727. for (var i = 0, marker; marker = this.markers[i]; i++){
  728. if (marker.infoWindow) {
  729. marker.infoWindow.close();
  730. }
  731. }
  732. };
  733. GMaps.prototype.removeMarker = function(marker) {
  734. for (var i = 0; i < this.markers.length; i++) {
  735. if (this.markers[i] === marker) {
  736. this.markers[i].setMap(null);
  737. this.markers.splice(i, 1);
  738. if(this.markerClusterer) {
  739. this.markerClusterer.removeMarker(marker);
  740. }
  741. GMaps.fire('marker_removed', marker, this);
  742. break;
  743. }
  744. }
  745. return marker;
  746. };
  747. GMaps.prototype.removeMarkers = function (collection) {
  748. var new_markers = [];
  749. if (typeof collection == 'undefined') {
  750. for (var i = 0; i < this.markers.length; i++) {
  751. var marker = this.markers[i];
  752. marker.setMap(null);
  753. GMaps.fire('marker_removed', marker, this);
  754. }
  755. if(this.markerClusterer && this.markerClusterer.clearMarkers) {
  756. this.markerClusterer.clearMarkers();
  757. }
  758. this.markers = new_markers;
  759. }
  760. else {
  761. for (var i = 0; i < collection.length; i++) {
  762. var index = this.markers.indexOf(collection[i]);
  763. if (index > -1) {
  764. var marker = this.markers[index];
  765. marker.setMap(null);
  766. if(this.markerClusterer) {
  767. this.markerClusterer.removeMarker(marker);
  768. }
  769. GMaps.fire('marker_removed', marker, this);
  770. }
  771. }
  772. for (var i = 0; i < this.markers.length; i++) {
  773. var marker = this.markers[i];
  774. if (marker.getMap() != null) {
  775. new_markers.push(marker);
  776. }
  777. }
  778. this.markers = new_markers;
  779. }
  780. };
  781. GMaps.prototype.drawOverlay = function(options) {
  782. var overlay = new google.maps.OverlayView(),
  783. auto_show = true;
  784. overlay.setMap(this.map);
  785. if (options.auto_show != null) {
  786. auto_show = options.auto_show;
  787. }
  788. overlay.onAdd = function() {
  789. var el = document.createElement('div');
  790. el.style.borderStyle = "none";
  791. el.style.borderWidth = "0px";
  792. el.style.position = "absolute";
  793. el.style.zIndex = 100;
  794. el.innerHTML = options.content;
  795. overlay.el = el;
  796. if (!options.layer) {
  797. options.layer = 'overlayLayer';
  798. }
  799. var panes = this.getPanes(),
  800. overlayLayer = panes[options.layer],
  801. stop_overlay_events = ['contextmenu', 'DOMMouseScroll', 'dblclick', 'mousedown'];
  802. overlayLayer.appendChild(el);
  803. for (var ev = 0; ev < stop_overlay_events.length; ev++) {
  804. (function(object, name) {
  805. google.maps.event.addDomListener(object, name, function(e){
  806. if (navigator.userAgent.toLowerCase().indexOf('msie') != -1 && document.all) {
  807. e.cancelBubble = true;
  808. e.returnValue = false;
  809. }
  810. else {
  811. e.stopPropagation();
  812. }
  813. });
  814. })(el, stop_overlay_events[ev]);
  815. }
  816. if (options.click) {
  817. panes.overlayMouseTarget.appendChild(overlay.el);
  818. google.maps.event.addDomListener(overlay.el, 'click', function() {
  819. options.click.apply(overlay, [overlay]);
  820. });
  821. }
  822. google.maps.event.trigger(this, 'ready');
  823. };
  824. overlay.draw = function() {
  825. var projection = this.getProjection(),
  826. pixel = projection.fromLatLngToDivPixel(new google.maps.LatLng(options.lat, options.lng));
  827. options.horizontalOffset = options.horizontalOffset || 0;
  828. options.verticalOffset = options.verticalOffset || 0;
  829. var el = overlay.el,
  830. content = el.children[0],
  831. content_height = content.clientHeight,
  832. content_width = content.clientWidth;
  833. switch (options.verticalAlign) {
  834. case 'top':
  835. el.style.top = (pixel.y - content_height + options.verticalOffset) + 'px';
  836. break;
  837. default:
  838. case 'middle':
  839. el.style.top = (pixel.y - (content_height / 2) + options.verticalOffset) + 'px';
  840. break;
  841. case 'bottom':
  842. el.style.top = (pixel.y + options.verticalOffset) + 'px';
  843. break;
  844. }
  845. switch (options.horizontalAlign) {
  846. case 'left':
  847. el.style.left = (pixel.x - content_width + options.horizontalOffset) + 'px';
  848. break;
  849. default:
  850. case 'center':
  851. el.style.left = (pixel.x - (content_width / 2) + options.horizontalOffset) + 'px';
  852. break;
  853. case 'right':
  854. el.style.left = (pixel.x + options.horizontalOffset) + 'px';
  855. break;
  856. }
  857. el.style.display = auto_show ? 'block' : 'none';
  858. if (!auto_show) {
  859. options.show.apply(this, [el]);
  860. }
  861. };
  862. overlay.onRemove = function() {
  863. var el = overlay.el;
  864. if (options.remove) {
  865. options.remove.apply(this, [el]);
  866. }
  867. else {
  868. overlay.el.parentNode.removeChild(overlay.el);
  869. overlay.el = null;
  870. }
  871. };
  872. this.overlays.push(overlay);
  873. return overlay;
  874. };
  875. GMaps.prototype.removeOverlay = function(overlay) {
  876. for (var i = 0; i < this.overlays.length; i++) {
  877. if (this.overlays[i] === overlay) {
  878. this.overlays[i].setMap(null);
  879. this.overlays.splice(i, 1);
  880. break;
  881. }
  882. }
  883. };
  884. GMaps.prototype.removeOverlays = function() {
  885. for (var i = 0, item; item = this.overlays[i]; i++) {
  886. item.setMap(null);
  887. }
  888. this.overlays = [];
  889. };
  890. GMaps.prototype.drawPolyline = function(options) {
  891. var path = [],
  892. points = options.path;
  893. if (points.length) {
  894. if (points[0][0] === undefined) {
  895. path = points;
  896. }
  897. else {
  898. for (var i = 0, latlng; latlng = points[i]; i++) {
  899. path.push(new google.maps.LatLng(latlng[0], latlng[1]));
  900. }
  901. }
  902. }
  903. var polyline_options = {
  904. map: this.map,
  905. path: path,
  906. strokeColor: options.strokeColor,
  907. strokeOpacity: options.strokeOpacity,
  908. strokeWeight: options.strokeWeight,
  909. geodesic: options.geodesic,
  910. clickable: true,
  911. editable: false,
  912. visible: true
  913. };
  914. if (options.hasOwnProperty("clickable")) {
  915. polyline_options.clickable = options.clickable;
  916. }
  917. if (options.hasOwnProperty("editable")) {
  918. polyline_options.editable = options.editable;
  919. }
  920. if (options.hasOwnProperty("icons")) {
  921. polyline_options.icons = options.icons;
  922. }
  923. if (options.hasOwnProperty("zIndex")) {
  924. polyline_options.zIndex = options.zIndex;
  925. }
  926. var polyline = new google.maps.Polyline(polyline_options);
  927. var polyline_events = ['click', 'dblclick', 'mousedown', 'mousemove', 'mouseout', 'mouseover', 'mouseup', 'rightclick'];
  928. for (var ev = 0; ev < polyline_events.length; ev++) {
  929. (function(object, name) {
  930. if (options[name]) {
  931. google.maps.event.addListener(object, name, function(e){
  932. options[name].apply(this, [e]);
  933. });
  934. }
  935. })(polyline, polyline_events[ev]);
  936. }
  937. this.polylines.push(polyline);
  938. GMaps.fire('polyline_added', polyline, this);
  939. return polyline;
  940. };
  941. GMaps.prototype.removePolyline = function(polyline) {
  942. for (var i = 0; i < this.polylines.length; i++) {
  943. if (this.polylines[i] === polyline) {
  944. this.polylines[i].setMap(null);
  945. this.polylines.splice(i, 1);
  946. GMaps.fire('polyline_removed', polyline, this);
  947. break;
  948. }
  949. }
  950. };
  951. GMaps.prototype.removePolylines = function() {
  952. for (var i = 0, item; item = this.polylines[i]; i++) {
  953. item.setMap(null);
  954. }
  955. this.polylines = [];
  956. };
  957. GMaps.prototype.drawCircle = function(options) {
  958. options = extend_object({
  959. map: this.map,
  960. center: new google.maps.LatLng(options.lat, options.lng)
  961. }, options);
  962. delete options.lat;
  963. delete options.lng;
  964. var polygon = new google.maps.Circle(options),
  965. polygon_events = ['click', 'dblclick', 'mousedown', 'mousemove', 'mouseout', 'mouseover', 'mouseup', 'rightclick'];
  966. for (var ev = 0; ev < polygon_events.length; ev++) {
  967. (function(object, name) {
  968. if (options[name]) {
  969. google.maps.event.addListener(object, name, function(e){
  970. options[name].apply(this, [e]);
  971. });
  972. }
  973. })(polygon, polygon_events[ev]);
  974. }
  975. this.polygons.push(polygon);
  976. return polygon;
  977. };
  978. GMaps.prototype.drawRectangle = function(options) {
  979. options = extend_object({
  980. map: this.map
  981. }, options);
  982. var latLngBounds = new google.maps.LatLngBounds(
  983. new google.maps.LatLng(options.bounds[0][0], options.bounds[0][1]),
  984. new google.maps.LatLng(options.bounds[1][0], options.bounds[1][1])
  985. );
  986. options.bounds = latLngBounds;
  987. var polygon = new google.maps.Rectangle(options),
  988. polygon_events = ['click', 'dblclick', 'mousedown', 'mousemove', 'mouseout', 'mouseover', 'mouseup', 'rightclick'];
  989. for (var ev = 0; ev < polygon_events.length; ev++) {
  990. (function(object, name) {
  991. if (options[name]) {
  992. google.maps.event.addListener(object, name, function(e){
  993. options[name].apply(this, [e]);
  994. });
  995. }
  996. })(polygon, polygon_events[ev]);
  997. }
  998. this.polygons.push(polygon);
  999. return polygon;
  1000. };
  1001. GMaps.prototype.drawPolygon = function(options) {
  1002. var useGeoJSON = false;
  1003. if(options.hasOwnProperty("useGeoJSON")) {
  1004. useGeoJSON = options.useGeoJSON;
  1005. }
  1006. delete options.useGeoJSON;
  1007. options = extend_object({
  1008. map: this.map
  1009. }, options);
  1010. if (useGeoJSON == false) {
  1011. options.paths = [options.paths.slice(0)];
  1012. }
  1013. if (options.paths.length > 0) {
  1014. if (options.paths[0].length > 0) {
  1015. options.paths = array_flat(array_map(options.paths, arrayToLatLng, useGeoJSON));
  1016. }
  1017. }
  1018. var polygon = new google.maps.Polygon(options),
  1019. polygon_events = ['click', 'dblclick', 'mousedown', 'mousemove', 'mouseout', 'mouseover', 'mouseup', 'rightclick'];
  1020. for (var ev = 0; ev < polygon_events.length; ev++) {
  1021. (function(object, name) {
  1022. if (options[name]) {
  1023. google.maps.event.addListener(object, name, function(e){
  1024. options[name].apply(this, [e]);
  1025. });
  1026. }
  1027. })(polygon, polygon_events[ev]);
  1028. }
  1029. this.polygons.push(polygon);
  1030. GMaps.fire('polygon_added', polygon, this);
  1031. return polygon;
  1032. };
  1033. GMaps.prototype.removePolygon = function(polygon) {
  1034. for (var i = 0; i < this.polygons.length; i++) {
  1035. if (this.polygons[i] === polygon) {
  1036. this.polygons[i].setMap(null);
  1037. this.polygons.splice(i, 1);
  1038. GMaps.fire('polygon_removed', polygon, this);
  1039. break;
  1040. }
  1041. }
  1042. };
  1043. GMaps.prototype.removePolygons = function() {
  1044. for (var i = 0, item; item = this.polygons[i]; i++) {
  1045. item.setMap(null);
  1046. }
  1047. this.polygons = [];
  1048. };
  1049. GMaps.prototype.getFromFusionTables = function(options) {
  1050. var events = options.events;
  1051. delete options.events;
  1052. var fusion_tables_options = options,
  1053. layer = new google.maps.FusionTablesLayer(fusion_tables_options);
  1054. for (var ev in events) {
  1055. (function(object, name) {
  1056. google.maps.event.addListener(object, name, function(e) {
  1057. events[name].apply(this, [e]);
  1058. });
  1059. })(layer, ev);
  1060. }
  1061. this.layers.push(layer);
  1062. return layer;
  1063. };
  1064. GMaps.prototype.loadFromFusionTables = function(options) {
  1065. var layer = this.getFromFusionTables(options);
  1066. layer.setMap(this.map);
  1067. return layer;
  1068. };
  1069. GMaps.prototype.getFromKML = function(options) {
  1070. var url = options.url,
  1071. events = options.events;
  1072. delete options.url;
  1073. delete options.events;
  1074. var kml_options = options,
  1075. layer = new google.maps.KmlLayer(url, kml_options);
  1076. for (var ev in events) {
  1077. (function(object, name) {
  1078. google.maps.event.addListener(object, name, function(e) {
  1079. events[name].apply(this, [e]);
  1080. });
  1081. })(layer, ev);
  1082. }
  1083. this.layers.push(layer);
  1084. return layer;
  1085. };
  1086. GMaps.prototype.loadFromKML = function(options) {
  1087. var layer = this.getFromKML(options);
  1088. layer.setMap(this.map);
  1089. return layer;
  1090. };
  1091. GMaps.prototype.addLayer = function(layerName, options) {
  1092. //var default_layers = ['weather', 'clouds', 'traffic', 'transit', 'bicycling', 'panoramio', 'places'];
  1093. options = options || {};
  1094. var layer;
  1095. switch(layerName) {
  1096. case 'weather': this.singleLayers.weather = layer = new google.maps.weather.WeatherLayer();
  1097. break;
  1098. case 'clouds': this.singleLayers.clouds = layer = new google.maps.weather.CloudLayer();
  1099. break;
  1100. case 'traffic': this.singleLayers.traffic = layer = new google.maps.TrafficLayer();
  1101. break;
  1102. case 'transit': this.singleLayers.transit = layer = new google.maps.TransitLayer();
  1103. break;
  1104. case 'bicycling': this.singleLayers.bicycling = layer = new google.maps.BicyclingLayer();
  1105. break;
  1106. case 'panoramio':
  1107. this.singleLayers.panoramio = layer = new google.maps.panoramio.PanoramioLayer();
  1108. layer.setTag(options.filter);
  1109. delete options.filter;
  1110. //click event
  1111. if (options.click) {
  1112. google.maps.event.addListener(layer, 'click', function(event) {
  1113. options.click(event);
  1114. delete options.click;
  1115. });
  1116. }
  1117. break;
  1118. case 'places':
  1119. this.singleLayers.places = layer = new google.maps.places.PlacesService(this.map);
  1120. //search, nearbySearch, radarSearch callback, Both are the same
  1121. if (options.search || options.nearbySearch || options.radarSearch) {
  1122. var placeSearchRequest = {
  1123. bounds : options.bounds || null,
  1124. keyword : options.keyword || null,
  1125. location : options.location || null,
  1126. name : options.name || null,
  1127. radius : options.radius || null,
  1128. rankBy : options.rankBy || null,
  1129. types : options.types || null
  1130. };
  1131. if (options.radarSearch) {
  1132. layer.radarSearch(placeSearchRequest, options.radarSearch);
  1133. }
  1134. if (options.search) {
  1135. layer.search(placeSearchRequest, options.search);
  1136. }
  1137. if (options.nearbySearch) {
  1138. layer.nearbySearch(placeSearchRequest, options.nearbySearch);
  1139. }
  1140. }
  1141. //textSearch callback
  1142. if (options.textSearch) {
  1143. var textSearchRequest = {
  1144. bounds : options.bounds || null,
  1145. location : options.location || null,
  1146. query : options.query || null,
  1147. radius : options.radius || null
  1148. };
  1149. layer.textSearch(textSearchRequest, options.textSearch);
  1150. }
  1151. break;
  1152. }
  1153. if (layer !== undefined) {
  1154. if (typeof layer.setOptions == 'function') {
  1155. layer.setOptions(options);
  1156. }
  1157. if (typeof layer.setMap == 'function') {
  1158. layer.setMap(this.map);
  1159. }
  1160. return layer;
  1161. }
  1162. };
  1163. GMaps.prototype.removeLayer = function(layer) {
  1164. if (typeof(layer) == "string" && this.singleLayers[layer] !== undefined) {
  1165. this.singleLayers[layer].setMap(null);
  1166. delete this.singleLayers[layer];
  1167. }
  1168. else {
  1169. for (var i = 0; i < this.layers.length; i++) {
  1170. if (this.layers[i] === layer) {
  1171. this.layers[i].setMap(null);
  1172. this.layers.splice(i, 1);
  1173. break;
  1174. }
  1175. }
  1176. }
  1177. };
  1178. var travelMode, unitSystem;
  1179. GMaps.prototype.getRoutes = function(options) {
  1180. switch (options.travelMode) {
  1181. case 'bicycling':
  1182. travelMode = google.maps.TravelMode.BICYCLING;
  1183. break;
  1184. case 'transit':
  1185. travelMode = google.maps.TravelMode.TRANSIT;
  1186. break;
  1187. case 'driving':
  1188. travelMode = google.maps.TravelMode.DRIVING;
  1189. break;
  1190. default:
  1191. travelMode = google.maps.TravelMode.WALKING;
  1192. break;
  1193. }
  1194. if (options.unitSystem === 'imperial') {
  1195. unitSystem = google.maps.UnitSystem.IMPERIAL;
  1196. }
  1197. else {
  1198. unitSystem = google.maps.UnitSystem.METRIC;
  1199. }
  1200. var base_options = {
  1201. avoidHighways: false,
  1202. avoidTolls: false,
  1203. optimizeWaypoints: false,
  1204. waypoints: []
  1205. },
  1206. request_options = extend_object(base_options, options);
  1207. request_options.origin = /string/.test(typeof options.origin) ? options.origin : new google.maps.LatLng(options.origin[0], options.origin[1]);
  1208. request_options.destination = /string/.test(typeof options.destination) ? options.destination : new google.maps.LatLng(options.destination[0], options.destination[1]);
  1209. request_options.travelMode = travelMode;
  1210. request_options.unitSystem = unitSystem;
  1211. delete request_options.callback;
  1212. delete request_options.error;
  1213. var self = this,
  1214. routes = [],
  1215. service = new google.maps.DirectionsService();
  1216. service.route(request_options, function(result, status) {
  1217. if (status === google.maps.DirectionsStatus.OK) {
  1218. for (var r in result.routes) {
  1219. if (result.routes.hasOwnProperty(r)) {
  1220. routes.push(result.routes[r]);
  1221. }
  1222. }
  1223. if (options.callback) {
  1224. options.callback(routes, result, status);
  1225. }
  1226. }
  1227. else {
  1228. if (options.error) {
  1229. options.error(result, status);
  1230. }
  1231. }
  1232. });
  1233. };
  1234. GMaps.prototype.removeRoutes = function() {
  1235. this.routes.length = 0;
  1236. };
  1237. GMaps.prototype.getElevations = function(options) {
  1238. options = extend_object({
  1239. locations: [],
  1240. path : false,
  1241. samples : 256
  1242. }, options);
  1243. if (options.locations.length > 0) {
  1244. if (options.locations[0].length > 0) {
  1245. options.locations = array_flat(array_map([options.locations], arrayToLatLng, false));
  1246. }
  1247. }
  1248. var callback = options.callback;
  1249. delete options.callback;
  1250. var service = new google.maps.ElevationService();
  1251. //location request
  1252. if (!options.path) {
  1253. delete options.path;
  1254. delete options.samples;
  1255. service.getElevationForLocations(options, function(result, status) {
  1256. if (callback && typeof(callback) === "function") {
  1257. callback(result, status);
  1258. }
  1259. });
  1260. //path request
  1261. } else {
  1262. var pathRequest = {
  1263. path : options.locations,
  1264. samples : options.samples
  1265. };
  1266. service.getElevationAlongPath(pathRequest, function(result, status) {
  1267. if (callback && typeof(callback) === "function") {
  1268. callback(result, status);
  1269. }
  1270. });
  1271. }
  1272. };
  1273. GMaps.prototype.cleanRoute = GMaps.prototype.removePolylines;
  1274. GMaps.prototype.renderRoute = function(options, renderOptions) {
  1275. var self = this,
  1276. panel = ((typeof renderOptions.panel === 'string') ? document.getElementById(renderOptions.panel.replace('#', '')) : renderOptions.panel),
  1277. display;
  1278. renderOptions.panel = panel;
  1279. renderOptions = extend_object({
  1280. map: this.map
  1281. }, renderOptions);
  1282. display = new google.maps.DirectionsRenderer(renderOptions);
  1283. this.getRoutes({
  1284. origin: options.origin,
  1285. destination: options.destination,
  1286. travelMode: options.travelMode,
  1287. waypoints: options.waypoints,
  1288. unitSystem: options.unitSystem,
  1289. error: options.error,
  1290. avoidHighways: options.avoidHighways,
  1291. avoidTolls: options.avoidTolls,
  1292. optimizeWaypoints: options.optimizeWaypoints,
  1293. callback: function(routes, response, status) {
  1294. if (status === google.maps.DirectionsStatus.OK) {
  1295. display.setDirections(response);
  1296. }
  1297. }
  1298. });
  1299. };
  1300. GMaps.prototype.drawRoute = function(options) {
  1301. var self = this;
  1302. this.getRoutes({
  1303. origin: options.origin,
  1304. destination: options.destination,
  1305. travelMode: options.travelMode,
  1306. waypoints: options.waypoints,
  1307. unitSystem: options.unitSystem,
  1308. error: options.error,
  1309. avoidHighways: options.avoidHighways,
  1310. avoidTolls: options.avoidTolls,
  1311. optimizeWaypoints: options.optimizeWaypoints,
  1312. callback: function(routes) {
  1313. if (routes.length > 0) {
  1314. var polyline_options = {
  1315. path: routes[routes.length - 1].overview_path,
  1316. strokeColor: options.strokeColor,
  1317. strokeOpacity: options.strokeOpacity,
  1318. strokeWeight: options.strokeWeight
  1319. };
  1320. if (options.hasOwnProperty("icons")) {
  1321. polyline_options.icons = options.icons;
  1322. }
  1323. self.drawPolyline(polyline_options);
  1324. if (options.callback) {
  1325. options.callback(routes[routes.length - 1]);
  1326. }
  1327. }
  1328. }
  1329. });
  1330. };
  1331. GMaps.prototype.travelRoute = function(options) {
  1332. if (options.origin && options.destination) {
  1333. this.getRoutes({
  1334. origin: options.origin,
  1335. destination: options.destination,
  1336. travelMode: options.travelMode,
  1337. waypoints : options.waypoints,
  1338. unitSystem: options.unitSystem,
  1339. error: options.error,
  1340. callback: function(e) {
  1341. //start callback
  1342. if (e.length > 0 && options.start) {
  1343. options.start(e[e.length - 1]);
  1344. }
  1345. //step callback
  1346. if (e.length > 0 && options.step) {
  1347. var route = e[e.length - 1];
  1348. if (route.legs.length > 0) {
  1349. var steps = route.legs[0].steps;
  1350. for (var i = 0, step; step = steps[i]; i++) {
  1351. step.step_number = i;
  1352. options.step(step, (route.legs[0].steps.length - 1));
  1353. }
  1354. }
  1355. }
  1356. //end callback
  1357. if (e.length > 0 && options.end) {
  1358. options.end(e[e.length - 1]);
  1359. }
  1360. }
  1361. });
  1362. }
  1363. else if (options.route) {
  1364. if (options.route.legs.length > 0) {
  1365. var steps = options.route.legs[0].steps;
  1366. for (var i = 0, step; step = steps[i]; i++) {
  1367. step.step_number = i;
  1368. options.step(step);
  1369. }
  1370. }
  1371. }
  1372. };
  1373. GMaps.prototype.drawSteppedRoute = function(options) {
  1374. var self = this;
  1375. if (options.origin && options.destination) {
  1376. this.getRoutes({
  1377. origin: options.origin,
  1378. destination: options.destination,
  1379. travelMode: options.travelMode,
  1380. waypoints : options.waypoints,
  1381. error: options.error,
  1382. callback: function(e) {
  1383. //start callback
  1384. if (e.length > 0 && options.start) {
  1385. options.start(e[e.length - 1]);
  1386. }
  1387. //step callback
  1388. if (e.length > 0 && options.step) {
  1389. var route = e[e.length - 1];
  1390. if (route.legs.length > 0) {
  1391. var steps = route.legs[0].steps;
  1392. for (var i = 0, step; step = steps[i]; i++) {
  1393. step.step_number = i;
  1394. var polyline_options = {
  1395. path: step.path,
  1396. strokeColor: options.strokeColor,
  1397. strokeOpacity: options.strokeOpacity,
  1398. strokeWeight: options.strokeWeight
  1399. };
  1400. if (options.hasOwnProperty("icons")) {
  1401. polyline_options.icons = options.icons;
  1402. }
  1403. self.drawPolyline(polyline_options);
  1404. options.step(step, (route.legs[0].steps.length - 1));
  1405. }
  1406. }
  1407. }
  1408. //end callback
  1409. if (e.length > 0 && options.end) {
  1410. options.end(e[e.length - 1]);
  1411. }
  1412. }
  1413. });
  1414. }
  1415. else if (options.route) {
  1416. if (options.route.legs.length > 0) {
  1417. var steps = options.route.legs[0].steps;
  1418. for (var i = 0, step; step = steps[i]; i++) {
  1419. step.step_number = i;
  1420. var polyline_options = {
  1421. path: step.path,
  1422. strokeColor: options.strokeColor,
  1423. strokeOpacity: options.strokeOpacity,
  1424. strokeWeight: options.strokeWeight
  1425. };
  1426. if (options.hasOwnProperty("icons")) {
  1427. polyline_options.icons = options.icons;
  1428. }
  1429. self.drawPolyline(polyline_options);
  1430. options.step(step);
  1431. }
  1432. }
  1433. }
  1434. };
  1435. GMaps.Route = function(options) {
  1436. this.origin = options.origin;
  1437. this.destination = options.destination;
  1438. this.waypoints = options.waypoints;
  1439. this.map = options.map;
  1440. this.route = options.route;
  1441. this.step_count = 0;
  1442. this.steps = this.route.legs[0].steps;
  1443. this.steps_length = this.steps.length;
  1444. var polyline_options = {
  1445. path: new google.maps.MVCArray(),
  1446. strokeColor: options.strokeColor,
  1447. strokeOpacity: options.strokeOpacity,
  1448. strokeWeight: options.strokeWeight
  1449. };
  1450. if (options.hasOwnProperty("icons")) {
  1451. polyline_options.icons = options.icons;
  1452. }
  1453. this.polyline = this.map.drawPolyline(polyline_options).getPath();
  1454. };
  1455. GMaps.Route.prototype.getRoute = function(options) {
  1456. var self = this;
  1457. this.map.getRoutes({
  1458. origin : this.origin,
  1459. destination : this.destination,
  1460. travelMode : options.travelMode,
  1461. waypoints : this.waypoints || [],
  1462. error: options.error,
  1463. callback : function() {
  1464. self.route = e[0];
  1465. if (options.callback) {
  1466. options.callback.call(self);
  1467. }
  1468. }
  1469. });
  1470. };
  1471. GMaps.Route.prototype.back = function() {
  1472. if (this.step_count > 0) {
  1473. this.step_count--;
  1474. var path = this.route.legs[0].steps[this.step_count].path;
  1475. for (var p in path){
  1476. if (path.hasOwnProperty(p)){
  1477. this.polyline.pop();
  1478. }
  1479. }
  1480. }
  1481. };
  1482. GMaps.Route.prototype.forward = function() {
  1483. if (this.step_count < this.steps_length) {
  1484. var path = this.route.legs[0].steps[this.step_count].path;
  1485. for (var p in path){
  1486. if (path.hasOwnProperty(p)){
  1487. this.polyline.push(path[p]);
  1488. }
  1489. }
  1490. this.step_count++;
  1491. }
  1492. };
  1493. GMaps.prototype.checkGeofence = function(lat, lng, fence) {
  1494. return fence.containsLatLng(new google.maps.LatLng(lat, lng));
  1495. };
  1496. GMaps.prototype.checkMarkerGeofence = function(marker, outside_callback) {
  1497. if (marker.fences) {
  1498. for (var i = 0, fence; fence = marker.fences[i]; i++) {
  1499. var pos = marker.getPosition();
  1500. if (!this.checkGeofence(pos.lat(), pos.lng(), fence)) {
  1501. outside_callback(marker, fence);
  1502. }
  1503. }
  1504. }
  1505. };
  1506. GMaps.prototype.toImage = function(options) {
  1507. var options = options || {},
  1508. static_map_options = {};
  1509. static_map_options['size'] = options['size'] || [this.el.clientWidth, this.el.clientHeight];
  1510. static_map_options['lat'] = this.getCenter().lat();
  1511. static_map_options['lng'] = this.getCenter().lng();
  1512. if (this.markers.length > 0) {
  1513. static_map_options['markers'] = [];
  1514. for (var i = 0; i < this.markers.length; i++) {
  1515. static_map_options['markers'].push({
  1516. lat: this.markers[i].getPosition().lat(),
  1517. lng: this.markers[i].getPosition().lng()
  1518. });
  1519. }
  1520. }
  1521. if (this.polylines.length > 0) {
  1522. var polyline = this.polylines[0];
  1523. static_map_options['polyline'] = {};
  1524. static_map_options['polyline']['path'] = google.maps.geometry.encoding.encodePath(polyline.getPath());
  1525. static_map_options['polyline']['strokeColor'] = polyline.strokeColor
  1526. static_map_options['polyline']['strokeOpacity'] = polyline.strokeOpacity
  1527. static_map_options['polyline']['strokeWeight'] = polyline.strokeWeight
  1528. }
  1529. return GMaps.staticMapURL(static_map_options);
  1530. };
  1531. GMaps.staticMapURL = function(options){
  1532. var parameters = [],
  1533. data,
  1534. static_root = (location.protocol === 'file:' ? 'http:' : location.protocol ) + '//maps.googleapis.com/maps/api/staticmap';
  1535. if (options.url) {
  1536. static_root = options.url;
  1537. delete options.url;
  1538. }
  1539. static_root += '?';
  1540. var markers = options.markers;
  1541. delete options.markers;
  1542. if (!markers && options.marker) {
  1543. markers = [options.marker];
  1544. delete options.marker;
  1545. }
  1546. var styles = options.styles;
  1547. delete options.styles;
  1548. var polyline = options.polyline;
  1549. delete options.polyline;
  1550. /** Map options **/
  1551. if (options.center) {
  1552. parameters.push('center=' + options.center);
  1553. delete options.center;
  1554. }
  1555. else if (options.address) {
  1556. parameters.push('center=' + options.address);
  1557. delete options.address;
  1558. }
  1559. else if (options.lat) {
  1560. parameters.push(['center=', options.lat, ',', options.lng].join(''));
  1561. delete options.lat;
  1562. delete options.lng;
  1563. }
  1564. else if (options.visible) {
  1565. var visible = encodeURI(options.visible.join('|'));
  1566. parameters.push('visible=' + visible);
  1567. }
  1568. var size = options.size;
  1569. if (size) {
  1570. if (size.join) {
  1571. size = size.join('x');
  1572. }
  1573. delete options.size;
  1574. }
  1575. else {
  1576. size = '630x300';
  1577. }
  1578. parameters.push('size=' + size);
  1579. if (!options.zoom && options.zoom !== false) {
  1580. options.zoom = 15;
  1581. }
  1582. var sensor = options.hasOwnProperty('sensor') ? !!options.sensor : true;
  1583. delete options.sensor;
  1584. parameters.push('sensor=' + sensor);
  1585. for (var param in options) {
  1586. if (options.hasOwnProperty(param)) {
  1587. parameters.push(param + '=' + options[param]);
  1588. }
  1589. }
  1590. /** Markers **/
  1591. if (markers) {
  1592. var marker, loc;
  1593. for (var i = 0; data = markers[i]; i++) {
  1594. marker = [];
  1595. if (data.size && data.size !== 'normal') {
  1596. marker.push('size:' + data.size);
  1597. delete data.size;
  1598. }
  1599. else if (data.icon) {
  1600. marker.push('icon:' + encodeURI(data.icon));
  1601. delete data.icon;
  1602. }
  1603. if (data.color) {
  1604. marker.push('color:' + data.color.replace('#', '0x'));
  1605. delete data.color;
  1606. }
  1607. if (data.label) {
  1608. marker.push('label:' + data.label[0].toUpperCase());
  1609. delete data.label;
  1610. }
  1611. loc = (data.address ? data.address : data.lat + ',' + data.lng);
  1612. delete data.address;
  1613. delete data.lat;
  1614. delete data.lng;
  1615. for(var param in data){
  1616. if (data.hasOwnProperty(param)) {
  1617. marker.push(param + ':' + data[param]);
  1618. }
  1619. }
  1620. if (marker.length || i === 0) {
  1621. marker.push(loc);
  1622. marker = marker.join('|');
  1623. parameters.push('markers=' + encodeURI(marker));
  1624. }
  1625. // New marker without styles
  1626. else {
  1627. marker = parameters.pop() + encodeURI('|' + loc);
  1628. parameters.push(marker);
  1629. }
  1630. }
  1631. }
  1632. /** Map Styles **/
  1633. if (styles) {
  1634. for (var i = 0; i < styles.length; i++) {
  1635. var styleRule = [];
  1636. if (styles[i].featureType){
  1637. styleRule.push('feature:' + styles[i].featureType.toLowerCase());
  1638. }
  1639. if (styles[i].elementType) {
  1640. styleRule.push('element:' + styles[i].elementType.toLowerCase());
  1641. }
  1642. for (var j = 0; j < styles[i].stylers.length; j++) {
  1643. for (var p in styles[i].stylers[j]) {
  1644. var ruleArg = styles[i].stylers[j][p];
  1645. if (p == 'hue' || p == 'color') {
  1646. ruleArg = '0x' + ruleArg.substring(1);
  1647. }
  1648. styleRule.push(p + ':' + ruleArg);
  1649. }
  1650. }
  1651. var rule = styleRule.join('|');
  1652. if (rule != '') {
  1653. parameters.push('style=' + rule);
  1654. }
  1655. }
  1656. }
  1657. /** Polylines **/
  1658. function parseColor(color, opacity) {
  1659. if (color[0] === '#'){
  1660. color = color.replace('#', '0x');
  1661. if (opacity) {
  1662. opacity = parseFloat(opacity);
  1663. opacity = Math.min(1, Math.max(opacity, 0));
  1664. if (opacity === 0) {
  1665. return '0x00000000';
  1666. }
  1667. opacity = (opacity * 255).toString(16);
  1668. if (opacity.length === 1) {
  1669. opacity += opacity;
  1670. }
  1671. color = color.slice(0,8) + opacity;
  1672. }
  1673. }
  1674. return color;
  1675. }
  1676. if (polyline) {
  1677. data = polyline;
  1678. polyline = [];
  1679. if (data.strokeWeight) {
  1680. polyline.push('weight:' + parseInt(data.strokeWeight, 10));
  1681. }
  1682. if (data.strokeColor) {
  1683. var color = parseColor(data.strokeColor, data.strokeOpacity);
  1684. polyline.push('color:' + color);
  1685. }
  1686. if (data.fillColor) {
  1687. var fillcolor = parseColor(data.fillColor, data.fillOpacity);
  1688. polyline.push('fillcolor:' + fillcolor);
  1689. }
  1690. var path = data.path;
  1691. if (path.join) {
  1692. for (var j=0, pos; pos=path[j]; j++) {
  1693. polyline.push(pos.join(','));
  1694. }
  1695. }
  1696. else {
  1697. polyline.push('enc:' + path);
  1698. }
  1699. polyline = polyline.join('|');
  1700. parameters.push('path=' + encodeURI(polyline));
  1701. }
  1702. /** Retina support **/
  1703. var dpi = window.devicePixelRatio || 1;
  1704. parameters.push('scale=' + dpi);
  1705. parameters = parameters.join('&');
  1706. return static_root + parameters;
  1707. };
  1708. GMaps.prototype.addMapType = function(mapTypeId, options) {
  1709. if (options.hasOwnProperty("getTileUrl") && typeof(options["getTileUrl"]) == "function") {
  1710. options.tileSize = options.tileSize || new google.maps.Size(256, 256);
  1711. var mapType = new google.maps.ImageMapType(options);
  1712. this.map.mapTypes.set(mapTypeId, mapType);
  1713. }
  1714. else {
  1715. throw "'getTileUrl' function required.";
  1716. }
  1717. };
  1718. GMaps.prototype.addOverlayMapType = function(options) {
  1719. if (options.hasOwnProperty("getTile") && typeof(options["getTile"]) == "function") {
  1720. var overlayMapTypeIndex = options.index;
  1721. delete options.index;
  1722. this.map.overlayMapTypes.insertAt(overlayMapTypeIndex, options);
  1723. }
  1724. else {
  1725. throw "'getTile' function required.";
  1726. }
  1727. };
  1728. GMaps.prototype.removeOverlayMapType = function(overlayMapTypeIndex) {
  1729. this.map.overlayMapTypes.removeAt(overlayMapTypeIndex);
  1730. };
  1731. GMaps.prototype.addStyle = function(options) {
  1732. var styledMapType = new google.maps.StyledMapType(options.styles, { name: options.styledMapName });
  1733. this.map.mapTypes.set(options.mapTypeId, styledMapType);
  1734. };
  1735. GMaps.prototype.setStyle = function(mapTypeId) {
  1736. this.map.setMapTypeId(mapTypeId);
  1737. };
  1738. GMaps.prototype.createPanorama = function(streetview_options) {
  1739. if (!streetview_options.hasOwnProperty('lat') || !streetview_options.hasOwnProperty('lng')) {
  1740. streetview_options.lat = this.getCenter().lat();
  1741. streetview_options.lng = this.getCenter().lng();
  1742. }
  1743. this.panorama = GMaps.createPanorama(streetview_options);
  1744. this.map.setStreetView(this.panorama);
  1745. return this.panorama;
  1746. };
  1747. GMaps.createPanorama = function(options) {
  1748. var el = getElementById(options.el, options.context);
  1749. options.position = new google.maps.LatLng(options.lat, options.lng);
  1750. delete options.el;
  1751. delete options.context;
  1752. delete options.lat;
  1753. delete options.lng;
  1754. var streetview_events = ['closeclick', 'links_changed', 'pano_changed', 'position_changed', 'pov_changed', 'resize', 'visible_changed'],
  1755. streetview_options = extend_object({visible : true}, options);
  1756. for (var i = 0; i < streetview_events.length; i++) {
  1757. delete streetview_options[streetview_events[i]];
  1758. }
  1759. var panorama = new google.maps.StreetViewPanorama(el, streetview_options);
  1760. for (var i = 0; i < streetview_events.length; i++) {
  1761. (function(object, name) {
  1762. if (options[name]) {
  1763. google.maps.event.addListener(object, name, function(){
  1764. options[name].apply(this);
  1765. });
  1766. }
  1767. })(panorama, streetview_events[i]);
  1768. }
  1769. return panorama;
  1770. };
  1771. GMaps.prototype.on = function(event_name, handler) {
  1772. return GMaps.on(event_name, this, handler);
  1773. };
  1774. GMaps.prototype.off = function(event_name) {
  1775. GMaps.off(event_name, this);
  1776. };
  1777. GMaps.prototype.once = function(event_name, handler) {
  1778. return GMaps.once(event_name, this, handler);
  1779. };
  1780. GMaps.custom_events = ['marker_added', 'marker_removed', 'polyline_added', 'polyline_removed', 'polygon_added', 'polygon_removed', 'geolocated', 'geolocation_failed'];
  1781. GMaps.on = function(event_name, object, handler) {
  1782. if (GMaps.custom_events.indexOf(event_name) == -1) {
  1783. if(object instanceof GMaps) object = object.map;
  1784. return google.maps.event.addListener(object, event_name, handler);
  1785. }
  1786. else {
  1787. var registered_event = {
  1788. handler : handler,
  1789. eventName : event_name
  1790. };
  1791. object.registered_events[event_name] = object.registered_events[event_name] || [];
  1792. object.registered_events[event_name].push(registered_event);
  1793. return registered_event;
  1794. }
  1795. };
  1796. GMaps.off = function(event_name, object) {
  1797. if (GMaps.custom_events.indexOf(event_name) == -1) {
  1798. if(object instanceof GMaps) object = object.map;
  1799. google.maps.event.clearListeners(object, event_name);
  1800. }
  1801. else {
  1802. object.registered_events[event_name] = [];
  1803. }
  1804. };
  1805. GMaps.once = function(event_name, object, handler) {
  1806. if (GMaps.custom_events.indexOf(event_name) == -1) {
  1807. if(object instanceof GMaps) object = object.map;
  1808. return google.maps.event.addListenerOnce(object, event_name, handler);
  1809. }
  1810. };
  1811. GMaps.fire = function(event_name, object, scope) {
  1812. if (GMaps.custom_events.indexOf(event_name) == -1) {
  1813. google.maps.event.trigger(object, event_name, Array.prototype.slice.apply(arguments).slice(2));
  1814. }
  1815. else {
  1816. if(event_name in scope.registered_events) {
  1817. var firing_events = scope.registered_events[event_name];
  1818. for(var i = 0; i < firing_events.length; i++) {
  1819. (function(handler, scope, object) {
  1820. handler.apply(scope, [object]);
  1821. })(firing_events[i]['handler'], scope, object);
  1822. }
  1823. }
  1824. }
  1825. };
  1826. GMaps.geolocate = function(options) {
  1827. var complete_callback = options.always || options.complete;
  1828. if (navigator.geolocation) {
  1829. navigator.geolocation.getCurrentPosition(function(position) {
  1830. options.success(position);
  1831. if (complete_callback) {
  1832. complete_callback();
  1833. }
  1834. }, function(error) {
  1835. options.error(error);
  1836. if (complete_callback) {
  1837. complete_callback();
  1838. }
  1839. }, options.options);
  1840. }
  1841. else {
  1842. options.not_supported();
  1843. if (complete_callback) {
  1844. complete_callback();
  1845. }
  1846. }
  1847. };
  1848. GMaps.geocode = function(options) {
  1849. this.geocoder = new google.maps.Geocoder();
  1850. var callback = options.callback;
  1851. if (options.hasOwnProperty('lat') && options.hasOwnProperty('lng')) {
  1852. options.latLng = new google.maps.LatLng(options.lat, options.lng);
  1853. }
  1854. delete options.lat;
  1855. delete options.lng;
  1856. delete options.callback;
  1857. this.geocoder.geocode(options, function(results, status) {
  1858. callback(results, status);
  1859. });
  1860. };
  1861. if (typeof window.google === 'object' && window.google.maps) {
  1862. //==========================
  1863. // Polygon containsLatLng
  1864. // https://github.com/tparkin/Google-Maps-Point-in-Polygon
  1865. // Poygon getBounds extension - google-maps-extensions
  1866. // http://code.google.com/p/google-maps-extensions/source/browse/google.maps.Polygon.getBounds.js
  1867. if (!google.maps.Polygon.prototype.getBounds) {
  1868. google.maps.Polygon.prototype.getBounds = function(latLng) {
  1869. var bounds = new google.maps.LatLngBounds();
  1870. var paths = this.getPaths();
  1871. var path;
  1872. for (var p = 0; p < paths.getLength(); p++) {
  1873. path = paths.getAt(p);
  1874. for (var i = 0; i < path.getLength(); i++) {
  1875. bounds.extend(path.getAt(i));
  1876. }
  1877. }
  1878. return bounds;
  1879. };
  1880. }
  1881. if (!google.maps.Polygon.prototype.containsLatLng) {
  1882. // Polygon containsLatLng - method to determine if a latLng is within a polygon
  1883. google.maps.Polygon.prototype.containsLatLng = function(latLng) {
  1884. // Exclude points outside of bounds as there is no way they are in the poly
  1885. var bounds = this.getBounds();
  1886. if (bounds !== null && !bounds.contains(latLng)) {
  1887. return false;
  1888. }
  1889. // Raycast point in polygon method
  1890. var inPoly = false;
  1891. var numPaths = this.getPaths().getLength();
  1892. for (var p = 0; p < numPaths; p++) {
  1893. var path = this.getPaths().getAt(p);
  1894. var numPoints = path.getLength();
  1895. var j = numPoints - 1;
  1896. for (var i = 0; i < numPoints; i++) {
  1897. var vertex1 = path.getAt(i);
  1898. var vertex2 = path.getAt(j);
  1899. if (vertex1.lng() < latLng.lng() && vertex2.lng() >= latLng.lng() || vertex2.lng() < latLng.lng() && vertex1.lng() >= latLng.lng()) {
  1900. if (vertex1.lat() + (latLng.lng() - vertex1.lng()) / (vertex2.lng() - vertex1.lng()) * (vertex2.lat() - vertex1.lat()) < latLng.lat()) {
  1901. inPoly = !inPoly;
  1902. }
  1903. }
  1904. j = i;
  1905. }
  1906. }
  1907. return inPoly;
  1908. };
  1909. }
  1910. if (!google.maps.Circle.prototype.containsLatLng) {
  1911. google.maps.Circle.prototype.containsLatLng = function(latLng) {
  1912. if (google.maps.geometry) {
  1913. return google.maps.geometry.spherical.computeDistanceBetween(this.getCenter(), latLng) <= this.getRadius();
  1914. }
  1915. else {
  1916. return true;
  1917. }
  1918. };
  1919. }
  1920. google.maps.Rectangle.prototype.containsLatLng = function(latLng) {
  1921. return this.getBounds().contains(latLng);
  1922. };
  1923. google.maps.LatLngBounds.prototype.containsLatLng = function(latLng) {
  1924. return this.contains(latLng);
  1925. };
  1926. google.maps.Marker.prototype.setFences = function(fences) {
  1927. this.fences = fences;
  1928. };
  1929. google.maps.Marker.prototype.addFence = function(fence) {
  1930. this.fences.push(fence);
  1931. };
  1932. google.maps.Marker.prototype.getId = function() {
  1933. return this['__gm_id'];
  1934. };
  1935. }
  1936. //==========================
  1937. // Array indexOf
  1938. // https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/indexOf
  1939. if (!Array.prototype.indexOf) {
  1940. Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) {
  1941. "use strict";
  1942. if (this == null) {
  1943. throw new TypeError();
  1944. }
  1945. var t = Object(this);
  1946. var len = t.length >>> 0;
  1947. if (len === 0) {
  1948. return -1;
  1949. }
  1950. var n = 0;
  1951. if (arguments.length > 1) {
  1952. n = Number(arguments[1]);
  1953. if (n != n) { // shortcut for verifying if it's NaN
  1954. n = 0;
  1955. } else if (n != 0 && n != Infinity && n != -Infinity) {
  1956. n = (n > 0 || -1) * Math.floor(Math.abs(n));
  1957. }
  1958. }
  1959. if (n >= len) {
  1960. return -1;
  1961. }
  1962. var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0);
  1963. for (; k < len; k++) {
  1964. if (k in t && t[k] === searchElement) {
  1965. return k;
  1966. }
  1967. }
  1968. return -1;
  1969. }
  1970. }
  1971. return GMaps;
  1972. }));