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