/** * Extend Google Maps API. */ google.setOnLoadCallback(function() { // See https://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; } } }); /** * Gmap ArcGIS wrapper. */ function gmapArcgis(config) { return { // Storable properties config: config, map: (config.map != undefined) ? config.map : null, // UI unblocker wrapper unblockUI: function() { jQuery.unblockUI(); }, // UI blocker wrapper blockUI: function() { jQuery.blockUI(); }, // Set the current map setMap: function(map) { this.map = map; }, // Get the default opacity of an layer element defaultOpacity: function(element, store) { store = (store != undefined) ? store : 'layers'; if (this.config[store][element] != undefined && this.config[store][element].opacity != undefined) { return this.config[store][element].opacity; } else { return 0.55; } }, // Add polygons from a given ArcGIS MapServer Layer showPolygon: function(params) { params.service = new gmaps.ags.MapService(params['uri']); params.overlay = new gmaps.ags.MapOverlay(params.service, { exportOptions: { layerIds: params['layers'], layerOption: 'show', layerDefinitions: (params['layerDefinitions'] != undefined) ? params['layerDefinitions'] : { }, }, }); params.overlay.setMap(this.map); params.overlay.setOpacity(params.opacity); this.identifyPolygon(params); if (params.callback == undefined) { // Default callback: remove the blockUI once the layer is shown google.maps.event.addListener(params.overlay.getMapService(), 'update', function() { this.unblockUI(); }); } else { google.maps.event.addListener(params.overlay.getMapService(), 'update', function() { params.callback(this.map, params) ; this.unblockUI(); }); } return params.overlay; }, // Add an identify callback to a layer identifyPolygon: function(params) { // See https://google-maps-utility-library-v3.googlecode.com/svn/trunk/arcgislink/examples/identify.js if (typeof params.identify != 'undefined') { var self = this; // Configure event listener params.identifyListener = google.maps.event.addListener(this.map, 'click', function(point) { params.identify.geometry = point.latLng; params.identify.bounds = self.map.getBounds(); params.identify.width = self.map.getDiv().offsetWidth; params.identify.height = self.map.getDiv().offsetHeight; // Configure infoWindow if (params.infowindow != undefined) { params.infowindow.close(); params.infowindow.setContent(''); params.infowindow.setPosition(point.latLng); } else { params.infowindow = new google.maps.InfoWindow({ content: '', position: point.latLng, }); } // Identify layers params.service.identify(params.identify, function(identify, err) { if (!err) { var layers = { }; var result = null; var layerId = null; // Sort results by layer for (var i in identify.results) { result = identify.results[i]; layerId = result.layerId; if (layers[layerId] == undefined) { layers[layerId] = [ result ]; } else { layers[layerId].push(result); } } // Callback only if layers is not empty if (layers.toSource() !== "({})") { params.identify.callback(layers, params.infowindow, err); } } }); }); } }, // Add a KML to the map showKML: function(element) { if (typeof this.config['kmls'][element].overlay == 'undefined') { this.config['kmls'][element].overlay = new google.maps.KmlLayer(this.config['kmls'][element].uri); } this.config['kmls'][element].overlay.setMap(this.map); this.config['kmls'][element].isVisible = true; }, // Add a KML layer into the map addKML: function(element) { if (typeof this.config['kmls'][element].overlay != 'undefined') { this.showKML(element); this.unblockUI(); return; } if (this.config['kmls'][element].overlayTime != undefined) { this.showOverlay(this.config['kmls'][element].overlayTime); } this.showKML(element); }, // Add a layer to the map addLayers: function(element) { this.config['layers'][element].opacity = this.defaultOpacity(element); if (typeof this.config['layers'][element].overlay != 'undefined') { this.config['layers'][element].overlay.setOpacity(this.config['layers'][element].opacity); this.identifyPolygon(this.config['layers'][element]); this.unblockUI(); return; } if (this.config['layers'][element].overlayTime != undefined) { this.showOverlay(this.config['layers'][element].overlayTime); } this.config['layers'][element].overlay = this.showPolygon(this.config['layers'][element]); }, // Add a slider layer in the map addSlider: function(layer, slider) { this.config['sliders'][slider].opacity = this.defaultOpacity(layer, 'sliders'); this.config['sliders'][slider].callback = this.sliderUpdateOpacity; this.config['sliders'][slider].layers = [layer]; if (typeof this.config['sliders'][slider].overlays[layer] != 'undefined') { this.config['sliders'][slider].overlays[layer].setOpacity(this.config['sliders'][slider].opacity); this.unblockUI(); } if (this.config['sliders'][slider].overlayTime != undefined) { this.showOverlay(this.config['sliders'][slider].overlayTime); } this.config['sliders'][slider].overlays[layer] = this.showPolygon(this.config['sliders'][slider]); }, // Add makers to the map addMarkers: function(element) { var self = this; if (this.config['markers'][element].overlay != undefined) { this.toggleMarkers(element); return; } else { this.config['markers'][element].overlay = []; } if (this.config['markers'][element].overlayTime != undefined) { this.showOverlay(this.config['markers'][element].overlayTime); } // Query parameters var query = { returnGeometry: true, geometry: (this.config['markers'][element].bounds != undefined) ? this.config['markers'][element].bounds : undefined, where: (this.config['markers'][element].where != undefined) ? this.config['markers'][element].where : '1=1', outFields: this.config['markers'][element].fields, }; var layer = new gmaps.ags.Layer(this.config['markers'][element].uri); // Configure infoWindow this.config['markers'][element].infowindow = new google.maps.InfoWindow({ content: '', }); // Execute query if (this.config['markers'][element].resultSetCallback != undefined) { layer.query(query, this.config['markers'][element].resultSetCallback); } else { layer.query(query, processResultSet); } // Process results function processResultSet(fset) { var fs = fset.features; var title; for (var i = 0, c = fs.length; i < c; i++) { var feature = fs[i]; if (self.config['markers'][element].title != undefined) { title = feature.attributes[self.config['markers'][element].title]; } else { title = feature.attributes.nome; } self.config['markers'][element].overlay[i] = {}; self.config['markers'][element].overlay[i].marker = new google.maps.Marker({ title: title, icon: self.config['markers'][element].icon, position: feature.geometry[0].getPosition(), map: self.map, }); // Use a closure so marker data remains available to the listeners self.config['markers'][element].overlay[i].addListener = function() { var marker = self.config['markers'][element].overlay[i].marker; var infowindow = self.config['markers'][element].infowindow; var content = self.config['markers'][element].content; var attributes = feature.attributes; google.maps.event.addListener(marker, 'click', function() { infowindow.setContent(content(attributes)); infowindow.open(self.map, marker); }); }; // Execute self.config['markers'][element].overlay[i].addListener(); } self.unblockUI(); } }, // Toggle KML visibility toggleKML: function(element) { if (this.config['kmls'][element].overlay == undefined) { return; } else if (this.config['kmls'][element].isVisible == true) { this.config['kmls'][element].isVisible = false; this.config['kmls'][element].overlay.setMap(); } else { this.config['kmls'][element].isVisible = true; this.config['kmls'][element].overlay.setMap(this.map); } }, // Toggle layer visibility toggleLayers: function(element) { this.config['layers'][element].overlay.setOpacity(0); if (this.config['layers'][element].identifyListener != undefined) { google.maps.event.removeListener(this.config['layers'][element].identifyListener); } }, // Toggle marker visibility toggleMarkers: function(element, raw) { var markers = (raw == true) ? element : this.config['markers'][element].overlay; for (i=0; i < markers.length; i++) { if (markers[i].marker.getVisible()) { markers[i].marker.setVisible(false); } else { markers[i].marker.setVisible(true); } } }, // Block the UI and show an overlay showOverlay: function(t) { if ($.browser.msie === false) { message = this.config.overlayMessage; if (this.config.overlayCss != undefined) { css = this.config.overlayCss; } else { css = { }; } if (t == false) { $.blockUI({ message: message, css: css, }); } else { $.blockUI({ message: message, css: css, timeout: t, }); } } }, // Change a element in the map changeElement: function(type, element, callback) { if (this.config[type][element] == undefined || this.config[type][element]['showOn'] == undefined) { return; } if (jQuery.inArray(this.config.mapName, this.config[type][element]['showOn']) != -1) { this[callback](element); } }, // Display slider sliderUpdate: function(layer, slider) { if (this.config['sliders'][slider].overlays == undefined) { this.config['sliders'][slider].overlays = [ ]; } if (this.config['sliders'][slider].overlays[layer] == undefined) { this.addSlider(layer, slider); } this.sliderUpdateOpacity(layer, slider); }, // Fix slider opacity sliderUpdateOpacity: function(layer, slider) { for (var i in this.config['sliders'][slider].overlays) { if (i == layer) { this.config['sliders'][slider].overlays[i].setOpacity(this.defaultOpacity(slider, 'sliders')); } else { this.config['sliders'][slider].overlays[i].setOpacity(0); } } // The second and all subsequent layers shall be intialized without opacity. this.sliderOpacity = 0; }, // jQuery slider wrapper slider: function(element, slider) { var self = this; var type = (self.config.sliders[slider].type != undefined) ? self.config.sliders[slider].type : 'slider'; if (type == 'selectToUISlider') { $(element).selectToUISlider({ sliderOptions: { slide: function(event, ui) { self.sliderUpdate.apply(self, [ ui.value, slider ]); } } }).hide(); } else { // Max is the number of layers in the service $(element).slider({ value: 1, min: -1, max: 11, step: 1, animate: true, change: function(event, ui) { self.sliderUpdate.apply(self, [ ui.value, slider ]); }, }); } }, /** * Returns the zoom level at which the given rectangular region fits in the map view. * The zoom level is computed for the currently selected map type. * * @param {google.maps.Map} map * @param {google.maps.LatLngBounds} bounds * @return {Number} zoom level * @see http://stackoverflow.com/questions/9837017/equivalent-of-getboundszoomlevel-in-gmaps-api-3 */ getZoomByBounds: function(bounds) { var map = this.map; var MAX_ZOOM = map.mapTypes.get(map.getMapTypeId()).maxZoom || 21; var MIN_ZOOM = map.mapTypes.get(map.getMapTypeId()).minZoom || 0; var ne = map.getProjection().fromLatLngToPoint(bounds.getNorthEast()); var sw = map.getProjection().fromLatLngToPoint(bounds.getSouthWest()); var worldCoordWidth = Math.abs(ne.x-sw.x); var worldCoordHeight = Math.abs(ne.y-sw.y); // Fit padding in pixels var FIT_PAD = 40; for (var zoom = MAX_ZOOM; zoom >= MIN_ZOOM; --zoom) { if (worldCoordWidth*(1<