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