/*! * GMaps.js v0.2.13 * http://hpneo.github.com/gmaps/ * * Copyright 2012, Gustavo Leon * Released under the MIT License. */ if(window.google && window.google.maps){ var GMaps = (function(global) { "use strict"; var doc = document; var getElementById = function(id, context) { var ele if('jQuery' in global && context){ ele = $("#"+id.replace('#', ''), context)[0] }else{ ele = doc.getElementById(id.replace('#', '')); }; return ele; }; var GMaps = function(options) { var self = this; window.context_menu = {}; if(typeof(options.div)=='string'){ this.div = getElementById(options.div, options.context); }else{this.div = options.div;}; this.div.style.width = options.width || this.div.scrollWidth || this.div.offsetWidth; this.div.style.height = options.height || this.div.scrollHeight || this.div.offsetHeight; this.controls = []; this.overlays = []; this.layers = []; // array with kml and ft 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_div = null; this.zoom = options.zoom || 15; //'Hybrid', 'Roadmap', 'Satellite' or 'Terrain' var mapType; if (options.mapType) { mapType = google.maps.MapTypeId[options.mapType.toUpperCase()]; } else { mapType = google.maps.MapTypeId.ROADMAP; } var map_center = new google.maps.LatLng(options.lat, options.lng); delete options.div; delete options.lat; delete options.lng; delete options.mapType; delete options.width; delete options.height; var zoomControlOpt = options.zoomControlOpt || { style: 'DEFAULT', position: 'TOP_LEFT' }; var zoomControl = options.zoomControl || true, 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; var map_base_options = { zoom: this.zoom, center: map_center, mapTypeId: mapType, panControl: panControl, zoomControl: zoomControl, zoomControlOptions: { style: google.maps.ZoomControlStyle[zoomControlStyle], // DEFAULT LARGE SMALL position: google.maps.ControlPosition[zoomControlPosition] }, mapTypeControl: mapTypeControl, scaleControl: scaleControl, streetViewControl: streetViewControl, overviewMapControl: overviewMapControl }; var map_options = extend_object(map_base_options, options); this.map = new google.maps.Map(this.div, map_options); // Context menus var buildContextMenuHTML = function(control, e) { var html = ''; var options = window.context_menu[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'); var context_menu_items_count = context_menu_items.length; for(var i=0;i 0) { if(options.paths[0].length > 0) { options.paths = array_map(options.paths, arrayToLatLng); } } var polygon = new google.maps.Polygon(options); var polygon_events = ['click', 'dblclick', 'mousedown', 'mousemove', 'mouseout', 'mouseover', 'mouseup', 'rightclick']; for (var ev = 0; ev < polygon_events.length; ev++) { (function(object, name) { google.maps.event.addListener(object, name, function(e){ if (options[name]) options[name].apply(this, [e]); }); })(polygon, polygon_events[ev]); } this.polygons.push(polygon); return polygon; }; this.removePolygon = this.removeOverlay; this.removePolygons = function() { for (var i=0, item; item=self.polygons[i]; i++){ item.setMap(null); } self.polygons = []; }; this.getFromFusionTables = function(options) { var events = options.events; delete options.events; var fusion_tables_options = options; var layer = new google.maps.FusionTablesLayer(fusion_tables_options); for (var ev in events) { (function(object, name) { google.maps.event.addListener(object, name, function(e){ events[name].apply(this, [e]); }); })(layer, ev); } this.layers.push(layer); return layer; }; this.loadFromFusionTables = function(options) { var layer = this.getFromFusionTables(options); layer.setMap(this.map); return layer; }; this.getFromKML = function(options) { var url = options.url; var events = options.events; delete options.url; delete options.events; var kml_options = options; var layer = new google.maps.KmlLayer(url, kml_options); for (var ev in events) { (function(object, name) { google.maps.event.addListener(object, name, function(e){ events[name].apply(this, [e]); }); })(layer, ev); } this.layers.push(layer); return layer; }; this.loadFromKML = function(options) { var layer = this.getFromKML(options); layer.setMap(this.map); return layer; }; // Services var travelMode, unitSystem; this.getRoutes = function(options) { switch (options.travelMode) { case 'bicycling': travelMode = google.maps.TravelMode.BICYCLING; break; case 'transit': travelMode = google.maps.TravelMode.TRANSIT; break; case 'driving': travelMode = google.maps.TravelMode.DRIVING; break; // case 'walking': default: travelMode = google.maps.TravelMode.WALKING; break; } if (options.unitSystem === 'imperial') { unitSystem = google.maps.UnitSystem.IMPERIAL; } else { unitSystem = google.maps.UnitSystem.METRIC; } var base_options = { avoidHighways: false, avoidTolls: false, optimizeWaypoints: false, waypoints: [] }; var request_options = extend_object(base_options, options); request_options.origin = new google.maps.LatLng(options.origin[0], options.origin[1]); request_options.destination = new google.maps.LatLng(options.destination[0], options.destination[1]); request_options.travelMode = travelMode; request_options.unitSystem = unitSystem; delete request_options.callback; var self = this; var service = new google.maps.DirectionsService(); service.route(request_options, function(result, status) { if (status === google.maps.DirectionsStatus.OK) { for (var r in result.routes) { if (result.routes.hasOwnProperty(r)) { self.routes.push(result.routes[r]); } } } if (options.callback) { options.callback(self.routes); } }); }; this.removeRoutes = function() { this.routes = []; }; this.getElevations = function(options) { options = extend_object({ locations: [], path : false, samples : 256 }, options); if(options.locations.length > 0) { if(options.locations[0].length > 0) { options.locations = array_map(options.locations, arrayToLatLng); } } var callback = options.callback; delete options.callback; var service = new google.maps.ElevationService(); //location request if (!options.path) { delete options.path; delete options.samples; service.getElevationForLocations(options, function(result, status){ if (callback && typeof(callback) === "function") { callback(result, status); } }); //path request } else { var pathRequest = { path : options.locations, samples : options.samples }; service.getElevationAlongPath(pathRequest, function(result, status){ if (callback && typeof(callback) === "function") { callback(result, status); } }); } }; // Alias for the method "drawRoute" this.cleanRoute = this.removePolylines; this.drawRoute = function(options) { var self = this; this.getRoutes({ origin: options.origin, destination: options.destination, travelMode: options.travelMode, waypoints : options.waypoints, callback: function(e) { if (e.length > 0) { self.drawPolyline({ path: e[e.length - 1].overview_path, strokeColor: options.strokeColor, strokeOpacity: options.strokeOpacity, strokeWeight: options.strokeWeight }); if (options.callback) { options.callback(e[e.length - 1]); } } } }); }; this.travelRoute = function(options) { if (options.origin && options.destination) { this.getRoutes({ origin: options.origin, destination: options.destination, travelMode: options.travelMode, waypoints : options.waypoints, callback: function(e) { //start callback if (e.length > 0 && options.start) { options.start(e[e.length - 1]); } //step callback if (e.length > 0 && options.step) { var route = e[e.length - 1]; if (route.legs.length > 0) { var steps = route.legs[0].steps; for (var i=0, step; step=steps[i]; i++) { step.step_number = i; options.step(step, (route.legs[0].steps.length - 1)); } } } //end callback if (e.length > 0 && options.end) { options.end(e[e.length - 1]); } } }); } else if (options.route) { if (options.route.legs.length > 0) { var steps = options.route.legs[0].steps; for (var i=0, step; step=steps[i]; i++) { step.step_number = i; options.step(step); } } } }; this.drawSteppedRoute = function(options) { if (options.origin && options.destination) { this.getRoutes({ origin: options.origin, destination: options.destination, travelMode: options.travelMode, waypoints : options.waypoints, callback: function(e) { //start callback if (e.length > 0 && options.start) { options.start(e[e.length - 1]); } //step callback if (e.length > 0 && options.step) { var route = e[e.length - 1]; if (route.legs.length > 0) { var steps = route.legs[0].steps; for (var i=0, step; step=steps[i]; i++) { step.step_number = i; self.drawPolyline({ path: step.path, strokeColor: options.strokeColor, strokeOpacity: options.strokeOpacity, strokeWeight: options.strokeWeight }); options.step(step, (route.legs[0].steps.length - 1)); } } } //end callback if (e.length > 0 && options.end) { options.end(e[e.length - 1]); } } }); } else if (options.route) { if (options.route.legs.length > 0) { var steps = options.route.legs[0].steps; for (var i=0, step; step=steps[i]; i++) { step.step_number = i; self.drawPolyline({ path: step.path, strokeColor: options.strokeColor, strokeOpacity: options.strokeOpacity, strokeWeight: options.strokeWeight }); options.step(step); } } } }; // Geofence this.checkGeofence = function(lat, lng, fence) { return fence.containsLatLng(new google.maps.LatLng(lat, lng)); }; this.checkMarkerGeofence = function(marker, outside_callback) { if (marker.fences) { for (var i=0, fence; fence=marker.fences[i]; i++) { var pos = marker.getPosition(); if (!self.checkGeofence(pos.lat(), pos.lng(), fence)) { outside_callback(marker, fence); } } } }; //add layers to the maps this.addLayer = function(layerName, options) { //var default_layers = ['weather', 'clouds', 'traffic', 'transit', 'bicycling', 'panoramio', 'places']; options = options || {}; var layer; switch(layerName) { case 'weather': this.singleLayers.weather = layer = new google.maps.weather.WeatherLayer(); break; case 'clouds': this.singleLayers.clouds = layer = new google.maps.weather.CloudLayer(); break; case 'traffic': this.singleLayers.traffic = layer = new google.maps.TrafficLayer(); break; case 'transit': this.singleLayers.transit = layer = new google.maps.TransitLayer(); break; case 'bicycling': this.singleLayers.bicycling = layer = new google.maps.BicyclingLayer(); break; case 'panoramio': this.singleLayers.panoramio = layer = new google.maps.panoramio.PanoramioLayer(); layer.setTag(options.filter); delete options.filter; //click event if(options.click) { google.maps.event.addListener(layer, 'click', function(event) { options.click(event); delete options.click; }); } break; case 'places': this.singleLayers.places = layer = new google.maps.places.PlacesService(this.map); //search and nearbySearch callback, Both are the same if(options.search || options.nearbySearch) { var placeSearchRequest = { bounds : options.bounds || null, keyword : options.keyword || null, location : options.location || null, name : options.name || null, radius : options.radius || null, rankBy : options.rankBy || null, types : options.types || null }; if(options.search) { layer.search(placeSearchRequest, options.search); } if(options.nearbySearch) { layer.nearbySearch(placeSearchRequest, options.nearbySearch); } } //textSearch callback if(options.textSearch) { var textSearchRequest = { bounds : options.bounds || null, location : options.location || null, query : options.query || null, radius : options.radius || null }; layer.textSearch(textSearchRequest, options.textSearch); } break; } if(layer !== undefined) { if(typeof layer.setOptions == 'function') { layer.setOptions(options); } if(typeof layer.setMap == 'function') { layer.setMap(this.map); } return layer; } }; //remove layers this.removeLayer = function(layerName) { if(this.singleLayers[layerName] !== undefined) { this.singleLayers[layerName].setMap(null); delete this.singleLayers[layerName]; } }; this.toImage = function(options) { var options = options || {}; var static_map_options = {}; static_map_options['size'] = options['size'] || [this.div.clientWidth, this.div.clientHeight]; static_map_options['lat'] = this.getCenter().lat(); static_map_options['lng'] = this.getCenter().lng(); if(this.markers.length > 0) { static_map_options['markers'] = []; for(var i=0; i < this.markers.length; i++) { static_map_options['markers'].push({ lat: this.markers[i].getPosition().lat(), lng: this.markers[i].getPosition().lng() }); } } if(this.polylines.length > 0) { var polyline = this.polylines[0]; static_map_options['polyline'] = {}; static_map_options['polyline']['path'] = google.maps.geometry.encoding.encodePath(polyline.getPath()); static_map_options['polyline']['strokeColor'] = polyline.strokeColor static_map_options['polyline']['strokeOpacity'] = polyline.strokeOpacity static_map_options['polyline']['strokeWeight'] = polyline.strokeWeight } return GMaps.staticMapURL(static_map_options); }; }; GMaps.Route = function(options) { this.map = options.map; this.route = options.route; this.step_count = 0; this.steps = this.route.legs[0].steps; this.steps_length = this.steps.length; this.polyline = this.map.drawPolyline({ path: new google.maps.MVCArray(), strokeColor: options.strokeColor, strokeOpacity: options.strokeOpacity, strokeWeight: options.strokeWeight }).getPath(); this.back = function() { if (this.step_count > 0) { this.step_count--; var path = this.route.legs[0].steps[this.step_count].path; for (var p in path){ if (path.hasOwnProperty(p)){ this.polyline.pop(); } } } }; this.forward = function() { if (this.step_count < this.steps_length) { var path = this.route.legs[0].steps[this.step_count].path; for (var p in path){ if (path.hasOwnProperty(p)){ this.polyline.push(path[p]); } } this.step_count++; } }; }; // Geolocation (Modern browsers only) GMaps.geolocate = function(options) { if (navigator.geolocation) { navigator.geolocation.getCurrentPosition(function(position) { options.success(position); if (options.always) { options.always(); } }, function(error) { options.error(error); if (options.always) { options.always(); } }, options.options); } else { options.not_supported(); if (options.always) { options.always(); } } }; // Geocoding GMaps.geocode = function(options) { this.geocoder = new google.maps.Geocoder(); var callback = options.callback; if (options.hasOwnProperty('lat') && options.hasOwnProperty('lng')) { options.latLng = new google.maps.LatLng(options.lat, options.lng); } delete options.lat; delete options.lng; delete options.callback; this.geocoder.geocode(options, function(results, status) { callback(results, status); }); }; // Static maps GMaps.staticMapURL = function(options){ var parameters = []; var data; var static_root = 'http://maps.googleapis.com/maps/api/staticmap'; if (options.url){ static_root = options.url; delete options.url; } static_root += '?'; var markers = options.markers; delete options.markers; if (!markers && options.marker){ markers = [options.marker]; delete options.marker; } var polyline = options.polyline; delete options.polyline; /** Map options **/ if (options.center){ parameters.push('center=' + options.center); delete options.center; } else if (options.address){ parameters.push('center=' + options.address); delete options.address; } else if (options.lat){ parameters.push(['center=', options.lat, ',', options.lng].join('')); delete options.lat; delete options.lng; } else if (options.visible){ var visible = encodeURI(options.visible.join('|')); parameters.push('visible=' + visible); } var size = options.size; if (size){ if (size.join){ size = size.join('x'); } delete options.size; } else { size = '630x300'; } parameters.push('size=' + size); if (!options.zoom){ options.zoom = 15; } var sensor = options.hasOwnProperty('sensor') ? !!options.sensor : true; delete options.sensor; parameters.push('sensor=' + sensor); for (var param in options){ if (options.hasOwnProperty(param)){ parameters.push(param + '=' + options[param]); } } /** Markers **/ if (markers){ var marker, loc; for (var i=0; data=markers[i]; i++){ marker = []; if (data.size && data.size !== 'normal'){ marker.push('size:' + data.size); } else if (data.icon){ marker.push('icon:' + encodeURI(data.icon)); } if (data.color){ marker.push('color:' + data.color.replace('#', '0x')); } if (data.label){ marker.push('label:' + data.label[0].toUpperCase()); } loc = (data.address ? data.address : data.lat + ',' + data.lng); if (marker.length || i === 0){ marker.push(loc); marker = marker.join('|'); parameters.push('markers=' + encodeURI(marker)); } // New marker without styles else { marker = parameters.pop() + encodeURI('|' + loc); parameters.push(marker); } } } /** Polylines **/ function parseColor(color, opacity){ if (color[0] === '#'){ color = color.replace('#', '0x'); if (opacity){ opacity = parseFloat(opacity); opacity = Math.min(1, Math.max(opacity, 0)); if (opacity === 0){ return '0x00000000'; } opacity = (opacity * 255).toString(16); if (opacity.length === 1){ opacity += opacity; } color = color.slice(0,8) + opacity; } } return color; } if (polyline){ data = polyline; polyline = []; if (data.strokeWeight){ polyline.push('weight:' + parseInt(data.strokeWeight, 10)); } if (data.strokeColor){ var color = parseColor(data.strokeColor, data.strokeOpacity); polyline.push('color:' + color); } if (data.fillColor){ var fillcolor = parseColor(data.fillColor, data.fillOpacity); polyline.push('fillcolor:' + fillcolor); } var path = data.path; if (path.join){ for (var j=0, pos; pos=path[j]; j++){ polyline.push(pos.join(',')); } } else { polyline.push('enc:' + path); } polyline = polyline.join('|'); parameters.push('path=' + encodeURI(polyline)); } parameters = parameters.join('&'); return static_root + parameters; }; //========================== // Polygon containsLatLng // https://github.com/tparkin/Google-Maps-Point-in-Polygon // Poygon getBounds extension - google-maps-extensions // http://code.google.com/p/google-maps-extensions/source/browse/google.maps.Polygon.getBounds.js if (!google.maps.Polygon.prototype.getBounds) { google.maps.Polygon.prototype.getBounds = function(latLng) { var bounds = new google.maps.LatLngBounds(); var paths = this.getPaths(); var path; for (var p = 0; p < paths.getLength(); p++) { path = paths.getAt(p); for (var i = 0; i < path.getLength(); i++) { bounds.extend(path.getAt(i)); } } return bounds; }; } // Polygon containsLatLng - method to determine if a latLng is within a polygon google.maps.Polygon.prototype.containsLatLng = function(latLng) { // Exclude points outside of bounds as there is no way they are in the poly var bounds = this.getBounds(); if (bounds !== null && !bounds.contains(latLng)) { return false; } // Raycast point in polygon method var inPoly = false; var numPaths = this.getPaths().getLength(); for (var p = 0; p < numPaths; p++) { var path = this.getPaths().getAt(p); var numPoints = path.getLength(); var j = numPoints - 1; for (var i = 0; i < numPoints; i++) { var vertex1 = path.getAt(i); var vertex2 = path.getAt(j); if (vertex1.lng() < latLng.lng() && vertex2.lng() >= latLng.lng() || vertex2.lng() < latLng.lng() && vertex1.lng() >= latLng.lng()) { if (vertex1.lat() + (latLng.lng() - vertex1.lng()) / (vertex2.lng() - vertex1.lng()) * (vertex2.lat() - vertex1.lat()) < latLng.lat()) { inPoly = !inPoly; } } j = i; } } return inPoly; }; google.maps.LatLngBounds.prototype.containsLatLng = function(latLng) { return this.contains(latLng); }; google.maps.Marker.prototype.setFences = function(fences) { this.fences = fences; }; google.maps.Marker.prototype.addFence = function(fence) { this.fences.push(fence); }; return GMaps; }(this)); var arrayToLatLng = function(coords) { return new google.maps.LatLng(coords[0], coords[1]); }; var extend_object = function(obj, new_obj) { if(obj === new_obj) return obj; for(var name in new_obj){ obj[name] = new_obj[name]; } return obj; }; var array_map = function(array, callback) { if (Array.prototype.map && array.map === Array.prototype.map) { return array.map(callback); } else { var array_return = []; var array_length = array.length; for(var i = 0; i < array_length; i++) { array_return.push(callback(array[i])); } return array_return; } } } /*Extension: Styled map*/ GMaps.prototype.addStyle = function(options){ var styledMapType = new google.maps.StyledMapType(options.styles, options.styledMapName); this.map.mapTypes.set(options.mapTypeId, styledMapType); }; GMaps.prototype.setStyle = function(mapTypeId){ this.map.setMapTypeId(mapTypeId); };