--- a/labs/openlayers/lib/OpenLayers/Layer/Google/v3.js +++ b/labs/openlayers/lib/OpenLayers/Layer/Google/v3.js @@ -1,1 +1,420 @@ - +/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the Clear BSD license. + * See http://svn.openlayers.org/trunk/openlayers/license.txt for the + * full text of the license. */ + + +/** + * @requires OpenLayers/Layer/Google.js + */ + +/** + * Constant: OpenLayers.Layer.Google.v3 + * + * Mixin providing functionality specific to the Google Maps API v3. Note that + * this layer configures the google.maps.map object with the "disableDefaultUI" + * option set to true. Using UI controls that the Google Maps API provides is + * not supported by the OpenLayers API. + */ +OpenLayers.Layer.Google.v3 = { + + /** + * Constant: DEFAULTS + * {Object} It is not recommended to change the properties set here. Note + * that Google.v3 layers only work when sphericalMercator is set to true. + * + * (code) + * { + * maxExtent: new OpenLayers.Bounds( + * -128 * 156543.0339, + * -128 * 156543.0339, + * 128 * 156543.0339, + * 128 * 156543.0339 + * ), + * sphericalMercator: true, + * maxResolution: 156543.0339, + * units: "m", + * projection: "EPSG:900913" + * } + * (end) + */ + DEFAULTS: { + maxExtent: new OpenLayers.Bounds( + -128 * 156543.0339, + -128 * 156543.0339, + 128 * 156543.0339, + 128 * 156543.0339 + ), + sphericalMercator: true, + maxResolution: 156543.0339, + units: "m", + projection: "EPSG:900913" + }, + + /** + * Method: loadMapObject + * Load the GMap and register appropriate event listeners. If we can't + * load GMap2, then display a warning message. + */ + loadMapObject:function() { + if (!this.type) { + this.type = google.maps.MapTypeId.ROADMAP; + } + var mapObject; + var cache = OpenLayers.Layer.Google.cache[this.map.id]; + if (cache) { + // there are already Google layers added to this map + mapObject = cache.mapObject; + // increment the layer count + ++cache.count; + } else { + // this is the first Google layer for this map + + var container = this.map.viewPortDiv; + var div = document.createElement("div"); + div.id = this.map.id + "_GMapContainer"; + div.style.position = "absolute"; + div.style.width = "100%"; + div.style.height = "100%"; + container.appendChild(div); + + // create GMap and shuffle elements + var center = this.map.getCenter(); + mapObject = new google.maps.Map(div, { + center: center ? + new google.maps.LatLng(center.lat, center.lon) : + new google.maps.LatLng(0, 0), + zoom: this.map.getZoom() || 0, + mapTypeId: this.type, + disableDefaultUI: true, + keyboardShortcuts: false, + draggable: false, + disableDoubleClickZoom: true, + scrollwheel: false + }); + + // cache elements for use by any other google layers added to + // this same map + cache = { + mapObject: mapObject, + count: 1 + }; + OpenLayers.Layer.Google.cache[this.map.id] = cache; + this.repositionListener = google.maps.event.addListenerOnce( + mapObject, + "center_changed", + OpenLayers.Function.bind(this.repositionMapElements, this) + ); + } + this.mapObject = mapObject; + this.setGMapVisibility(this.visibility); + }, + + /** + * Method: repositionMapElements + * + * Waits until powered by and terms of use elements are available and then + * moves them so they are clickable. + */ + repositionMapElements: function() { + + // This is the first time any Google layer in this mapObject has been + // made visible. The mapObject needs to know the container size. + google.maps.event.trigger(this.mapObject, "resize"); + + var div = this.mapObject.getDiv().firstChild; + if (!div || div.childNodes.length < 3) { + this.repositionTimer = window.setTimeout( + OpenLayers.Function.bind(this.repositionMapElements, this), + 250 + ); + return false; + } + + var cache = OpenLayers.Layer.Google.cache[this.map.id]; + var container = this.map.viewPortDiv; + + // move the ToS and branding stuff up to the container div + var termsOfUse = div.lastChild; + container.appendChild(termsOfUse); + termsOfUse.style.zIndex = "1100"; + termsOfUse.style.bottom = ""; + termsOfUse.className = "olLayerGoogleCopyright olLayerGoogleV3"; + termsOfUse.style.display = ""; + cache.termsOfUse = termsOfUse; + + var poweredBy = div.lastChild; + container.appendChild(poweredBy); + poweredBy.style.zIndex = "1100"; + poweredBy.style.bottom = ""; + poweredBy.className = "olLayerGooglePoweredBy olLayerGoogleV3 gmnoprint"; + poweredBy.style.display = ""; + cache.poweredBy = poweredBy; + + this.setGMapVisibility(this.visibility); + + }, + + /** + * APIMethod: onMapResize + */ + onMapResize: function() { + if (this.visibility) { + google.maps.event.trigger(this.mapObject, "resize"); + } else { + if (!this._resized) { + var layer = this; + google.maps.event.addListenerOnce(this.mapObject, "tilesloaded", function() { + delete layer._resized; + google.maps.event.trigger(layer.mapObject, "resize"); + layer.moveTo(layer.map.getCenter(), layer.map.getZoom()); + }); + } + this._resized = true; + } + }, + + /** + * Method: setGMapVisibility + * Display the GMap container and associated elements. + * + * Parameters: + * visible - {Boolean} Display the GMap elements. + */ + setGMapVisibility: function(visible) { + var cache = OpenLayers.Layer.Google.cache[this.map.id]; + if (cache) { + var type = this.type; + var layers = this.map.layers; + var layer; + for (var i=layers.length-1; i>=0; --i) { + layer = layers[i]; + if (layer instanceof OpenLayers.Layer.Google && + layer.visibility === true && layer.inRange === true) { + type = layer.type; + visible = true; + break; + } + } + var container = this.mapObject.getDiv(); + if (visible === true) { + this.mapObject.setMapTypeId(type); + container.style.left = ""; + if (cache.termsOfUse && cache.termsOfUse.style) { + cache.termsOfUse.style.left = ""; + cache.termsOfUse.style.display = ""; + cache.poweredBy.style.display = ""; + } + cache.displayed = this.id; + } else { + delete cache.displayed; + container.style.left = "-9999px"; + if (cache.termsOfUse && cache.termsOfUse.style) { + cache.termsOfUse.style.display = "none"; + // move ToU far to the left in addition to setting + // display to "none", because at the end of the GMap + // load sequence, display: none will be unset and ToU + // would be visible after loading a map with a google + // layer that is initially hidden. + cache.termsOfUse.style.left = "-9999px"; + cache.poweredBy.style.display = "none"; + } + } + } + }, + + /** + * Method: getMapContainer + * + * Returns: + * {DOMElement} the GMap container's div + */ + getMapContainer: function() { + return this.mapObject.getDiv(); + }, + + // + // TRANSLATION: MapObject Bounds <-> OpenLayers.Bounds + // + + /** + * APIMethod: getMapObjectBoundsFromOLBounds + * + * Parameters: + * olBounds - {} + * + * Returns: + * {Object} A MapObject Bounds, translated from olBounds + * Returns null if null value is passed in + */ + getMapObjectBoundsFromOLBounds: function(olBounds) { + var moBounds = null; + if (olBounds != null) { + var sw = this.sphericalMercator ? + this.inverseMercator(olBounds.bottom, olBounds.left) : + new OpenLayers.LonLat(olBounds.bottom, olBounds.left); + var ne = this.sphericalMercator ? + this.inverseMercator(olBounds.top, olBounds.right) : + new OpenLayers.LonLat(olBounds.top, olBounds.right); + moBounds = new google.maps.LatLngBounds( + new google.maps.LatLng(sw.lat, sw.lon), + new google.maps.LatLng(ne.lat, ne.lon) + ); + } + return moBounds; + }, + + + /************************************ + * * + * MapObject Interface Controls * + * * + ************************************/ + + + // LonLat - Pixel Translation + + /** + * APIMethod: getMapObjectLonLatFromMapObjectPixel + * + * Parameters: + * moPixel - {Object} MapObject Pixel format + * + * Returns: + * {Object} MapObject LonLat translated from MapObject Pixel + */ + getMapObjectLonLatFromMapObjectPixel: function(moPixel) { + var size = this.map.getSize(); + var lon = this.getLongitudeFromMapObjectLonLat(this.mapObject.center); + var lat = this.getLatitudeFromMapObjectLonLat(this.mapObject.center); + var res = this.map.getResolution(); + + var delta_x = moPixel.x - (size.w / 2); + var delta_y = moPixel.y - (size.h / 2); + + var lonlat = new OpenLayers.LonLat( + lon + delta_x * res, + lat - delta_y * res + ); + + if (this.wrapDateLine) { + lonlat = lonlat.wrapDateLine(this.maxExtent); + } + return this.getMapObjectLonLatFromLonLat(lonlat.lon, lonlat.lat); + }, + + /** + * APIMethod: getMapObjectPixelFromMapObjectLonLat + * + * Parameters: + * moLonLat - {Object} MapObject LonLat format + * + * Returns: + * {Object} MapObject Pixel transtlated from MapObject LonLat + */ + getMapObjectPixelFromMapObjectLonLat: function(moLonLat) { + var lon = this.getLongitudeFromMapObjectLonLat(moLonLat); + var lat = this.getLatitudeFromMapObjectLonLat(moLonLat); + var res = this.map.getResolution(); + var extent = this.map.getExtent(); + var px = new OpenLayers.Pixel( + (1/res * (lon - extent.left)), + (1/res * (extent.top - lat)) + ); + return this.getMapObjectPixelFromXY(px.x, px.y); + }, + + + /** + * APIMethod: setMapObjectCenter + * Set the mapObject to the specified center and zoom + * + * Parameters: + * center - {Object} MapObject LonLat format + * zoom - {int} MapObject zoom format + */ + setMapObjectCenter: function(center, zoom) { + this.mapObject.setOptions({ + center: center, + zoom: zoom + }); + }, + + + // Bounds + + /** + * APIMethod: getMapObjectZoomFromMapObjectBounds + * + * Parameters: + * moBounds - {Object} MapObject Bounds format + * + * Returns: + * {Object} MapObject Zoom for specified MapObject Bounds + */ + getMapObjectZoomFromMapObjectBounds: function(moBounds) { + return this.mapObject.getBoundsZoomLevel(moBounds); + }, + + /************************************ + * * + * MapObject Primitives * + * * + ************************************/ + + + // LonLat + + /** + * APIMethod: getMapObjectLonLatFromLonLat + * + * Parameters: + * lon - {Float} + * lat - {Float} + * + * Returns: + * {Object} MapObject LonLat built from lon and lat params + */ + getMapObjectLonLatFromLonLat: function(lon, lat) { + var gLatLng; + if(this.sphericalMercator) { + var lonlat = this.inverseMercator(lon, lat); + gLatLng = new google.maps.LatLng(lonlat.lat, lonlat.lon); + } else { + gLatLng = new google.maps.LatLng(lat, lon); + } + return gLatLng; + }, + + // Pixel + + /** + * APIMethod: getMapObjectPixelFromXY + * + * Parameters: + * x - {Integer} + * y - {Integer} + * + * Returns: + * {Object} MapObject Pixel from x and y parameters + */ + getMapObjectPixelFromXY: function(x, y) { + return new google.maps.Point(x, y); + }, + + /** + * APIMethod: destroy + * Clean up this layer. + */ + destroy: function() { + if (this.repositionListener) { + google.maps.event.removeListener(this.repositionListener); + } + if (this.repositionTimer) { + window.clearTimeout(this.repositionTimer); + } + OpenLayers.Layer.Google.prototype.destroy.apply(this, arguments); + } + +}; +