if (!(typeof window.google === 'object' && window.google.maps)) { throw 'Google Maps API is required. Please register the following JavaScript library http://maps.google.com/maps/api/js?sensor=true.' } var extend_object = function(obj, new_obj) { var name; if (obj === new_obj) { return obj; } for (name in new_obj) { obj[name] = new_obj[name]; } return obj; }; var replace_object = function(obj, replace) { var name; if (obj === replace) { return obj; } for (name in replace) { if (obj[name] != undefined) { obj[name] = replace[name]; } } return obj; }; var array_map = function(array, callback) { var original_callback_params = Array.prototype.slice.call(arguments, 2), array_return = [], array_length = array.length, i; if (Array.prototype.map && array.map === Array.prototype.map) { array_return = Array.prototype.map.call(array, function(item) { callback_params = original_callback_params; callback_params.splice(0, 0, item); return callback.apply(this, callback_params); }); } else { for (i = 0; i < array_length; i++) { callback_params = original_callback_params; callback_params.splice(0, 0, array[i]); array_return.push(callback.apply(this, callback_params)); } } return array_return; }; var array_flat = function(array) { var new_array = [], i; for (i = 0; i < array.length; i++) { new_array = new_array.concat(array[i]); } return new_array; }; var coordsToLatLngs = function(coords, useGeoJSON) { var first_coord = coords[0], second_coord = coords[1]; if (useGeoJSON) { first_coord = coords[1]; second_coord = coords[0]; } return new google.maps.LatLng(first_coord, second_coord); }; var arrayToLatLng = function(coords, useGeoJSON) { var i; for (i = 0; i < coords.length; i++) { if (coords[i].length > 0 && typeof(coords[i][0]) == "object") { coords[i] = arrayToLatLng(coords[i], useGeoJSON); } else { coords[i] = coordsToLatLngs(coords[i], useGeoJSON); } } return coords; }; var getElementById = function(id, context) { var element, id = id.replace('#', ''); if ('jQuery' in this && context) { element = $("#" + id, context)[0]; } else { element = document.getElementById(id); }; return element; }; var findAbsolutePosition = function(obj) { var curleft = 0, curtop = 0; if (obj.offsetParent) { do { curleft += obj.offsetLeft; curtop += obj.offsetTop; } while (obj = obj.offsetParent); } return [curleft, curtop]; }; var GMaps = (function(global) { "use strict"; var doc = document; var GMaps = function(options) { if (!this) return new GMaps(options); options.zoom = options.zoom || 15; options.mapType = options.mapType || 'roadmap'; var self = this, i, events_that_hide_context_menu = ['bounds_changed', 'center_changed', 'click', 'dblclick', 'drag', 'dragend', 'dragstart', 'idle', 'maptypeid_changed', 'projection_changed', 'resize', 'tilesloaded', 'zoom_changed'], events_that_doesnt_hide_context_menu = ['mousemove', 'mouseout', 'mouseover'], options_to_be_deleted = ['el', 'lat', 'lng', 'mapType', 'width', 'height', 'markerClusterer', 'enableNewStyle'], container_id = options.el || options.div, markerClustererFunction = options.markerClusterer, mapType = google.maps.MapTypeId[options.mapType.toUpperCase()], map_center = new google.maps.LatLng(options.lat, options.lng), zoomControl = options.zoomControl || true, zoomControlOpt = options.zoomControlOpt || { style: 'DEFAULT', position: 'TOP_LEFT' }, zoomControlStyle = zoomControlOpt.style || 'DEFAULT', zoomControlPosition = zoomControlOpt.position || 'TOP_LEFT', panControl = options.panControl || true, mapTypeControl = options.mapTypeControl || true, scaleControl = options.scaleControl || true, streetViewControl = options.streetViewControl || true, overviewMapControl = overviewMapControl || true, map_options = {}, map_base_options = { zoom: this.zoom, center: map_center, mapTypeId: mapType }, map_controls_options = { panControl: panControl, zoomControl: zoomControl, zoomControlOptions: { style: google.maps.ZoomControlStyle[zoomControlStyle], position: google.maps.ControlPosition[zoomControlPosition] }, mapTypeControl: mapTypeControl, scaleControl: scaleControl, streetViewControl: streetViewControl, overviewMapControl: overviewMapControl }; if (typeof(options.el) === 'string' || typeof(options.div) === 'string') { this.el = getElementById(container_id, options.context); } else { this.el = container_id; } if (typeof(this.el) === 'undefined' || this.el === null) { throw 'No element defined.'; } window.context_menu = window.context_menu || {}; window.context_menu[self.el.id] = {}; this.controls = []; this.overlays = []; this.layers = []; // array with kml/georss and fusiontables layers, can be as many this.singleLayers = {}; // object with the other layers, only one per layer this.markers = []; this.polylines = []; this.routes = []; this.polygons = []; this.infoWindow = null; this.overlay_el = null; this.zoom = options.zoom; this.registered_events = {}; this.el.style.width = options.width || this.el.scrollWidth || this.el.offsetWidth; this.el.style.height = options.height || this.el.scrollHeight || this.el.offsetHeight; google.maps.visualRefresh = options.enableNewStyle; for (i = 0; i < options_to_be_deleted.length; i++) { delete options[options_to_be_deleted[i]]; } if(options.disableDefaultUI != true) { map_base_options = extend_object(map_base_options, map_controls_options); } map_options = extend_object(map_base_options, options); for (i = 0; i < events_that_hide_context_menu.length; i++) { delete map_options[events_that_hide_context_menu[i]]; } for (i = 0; i < events_that_doesnt_hide_context_menu.length; i++) { delete map_options[events_that_doesnt_hide_context_menu[i]]; } this.map = new google.maps.Map(this.el, map_options); if (markerClustererFunction) { this.markerClusterer = markerClustererFunction.apply(this, [this.map]); } var buildContextMenuHTML = function(control, e) { var html = '', options = window.context_menu[self.el.id][control]; for (var i in options){ if (options.hasOwnProperty(i)) { var option = options[i]; html += '
  • ' + option.title + '
  • '; } } if (!getElementById('gmaps_context_menu')) return; var context_menu_element = getElementById('gmaps_context_menu'); context_menu_element.innerHTML = html; var context_menu_items = context_menu_element.getElementsByTagName('a'), context_menu_items_count = context_menu_items.length i; for (i = 0; i < context_menu_items_count; i++) { var context_menu_item = context_menu_items[i]; var assign_menu_item_action = function(ev){ ev.preventDefault(); options[this.id.replace(control + '_', '')].action.apply(self, [e]); self.hideContextMenu(); }; google.maps.event.clearListeners(context_menu_item, 'click'); google.maps.event.addDomListenerOnce(context_menu_item, 'click', assign_menu_item_action, false); } var position = findAbsolutePosition.apply(this, [self.el]), left = position[0] + e.pixel.x - 15, top = position[1] + e.pixel.y- 15; context_menu_element.style.left = left + "px"; context_menu_element.style.top = top + "px"; context_menu_element.style.display = 'block'; }; this.buildContextMenu = function(control, e) { if (control === 'marker') { e.pixel = {}; var overlay = new google.maps.OverlayView(); overlay.setMap(self.map); overlay.draw = function() { var projection = overlay.getProjection(), position = e.marker.getPosition(); e.pixel = projection.fromLatLngToContainerPixel(position); buildContextMenuHTML(control, e); }; } else { buildContextMenuHTML(control, e); } }; this.setContextMenu = function(options) { window.context_menu[self.el.id][options.control] = {}; var i, ul = doc.createElement('ul'); for (i in options.options) { if (options.options.hasOwnProperty(i)) { var option = options.options[i]; window.context_menu[self.el.id][options.control][option.name] = { title: option.title, action: option.action }; } } ul.id = 'gmaps_context_menu'; ul.style.display = 'none'; ul.style.position = 'absolute'; ul.style.minWidth = '100px'; ul.style.background = 'white'; ul.style.listStyle = 'none'; ul.style.padding = '8px'; ul.style.boxShadow = '2px 2px 6px #ccc'; doc.body.appendChild(ul); var context_menu_element = getElementById('gmaps_context_menu') google.maps.event.addDomListener(context_menu_element, 'mouseout', function(ev) { if (!ev.relatedTarget || !this.contains(ev.relatedTarget)) { window.setTimeout(function(){ context_menu_element.style.display = 'none'; }, 400); } }, false); }; this.hideContextMenu = function() { var context_menu_element = getElementById('gmaps_context_menu'); if (context_menu_element) { context_menu_element.style.display = 'none'; } }; var setupListener = function(object, name) { google.maps.event.addListener(object, name, function(e){ if (e == undefined) { e = this; } options[name].apply(this, [e]); self.hideContextMenu(); }); }; for (var ev = 0; ev < events_that_hide_context_menu.length; ev++) { var name = events_that_hide_context_menu[ev]; if (name in options) { setupListener(this.map, name); } } for (var ev = 0; ev < events_that_doesnt_hide_context_menu.length; ev++) { var name = events_that_doesnt_hide_context_menu[ev]; if (name in options) { setupListener(this.map, name); } } google.maps.event.addListener(this.map, 'rightclick', function(e) { if (options.rightclick) { options.rightclick.apply(this, [e]); } if(window.context_menu[self.el.id]['map'] != undefined) { self.buildContextMenu('map', e); } }); this.refresh = function() { google.maps.event.trigger(this.map, 'resize'); }; this.fitZoom = function() { var latLngs = [], markers_length = this.markers.length, i; for (i = 0; i < markers_length; i++) { latLngs.push(this.markers[i].getPosition()); } this.fitLatLngBounds(latLngs); }; this.fitLatLngBounds = function(latLngs) { var total = latLngs.length; var bounds = new google.maps.LatLngBounds(); for(var i=0; i < total; i++) { bounds.extend(latLngs[i]); } this.map.fitBounds(bounds); }; this.setCenter = function(lat, lng, callback) { this.map.panTo(new google.maps.LatLng(lat, lng)); if (callback) { callback(); } }; this.getElement = function() { return this.el; }; this.zoomIn = function(value) { value = value || 1; this.zoom = this.map.getZoom() + value; this.map.setZoom(this.zoom); }; this.zoomOut = function(value) { value = value || 1; this.zoom = this.map.getZoom() - value; this.map.setZoom(this.zoom); }; var native_methods = [], method; for (method in this.map) { if (typeof(this.map[method]) == 'function' && !this[method]) { native_methods.push(method); } } for (i=0; i < native_methods.length; i++) { (function(gmaps, scope, method_name) { gmaps[method_name] = function(){ return scope[method_name].apply(scope, arguments); }; })(this, this.map, native_methods[i]); } }; return GMaps; })(this);