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