1 /* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
2 * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
3 * full text of the license. */
7 * @requires OpenLayers/Layer/SphericalMercator.js
8 * @requires OpenLayers/Layer/EventPane.js
9 * @requires OpenLayers/Layer/FixedZoomLevels.js
10 * @requires OpenLayers/Console.js
14 * Class: OpenLayers.Layer.Google
17 * - <OpenLayers.Layer.SphericalMercator>
18 * - <OpenLayers.Layer.EventPane>
19 * - <OpenLayers.Layer.FixedZoomLevels>
21 OpenLayers.Layer.Google = OpenLayers.Class(
22 OpenLayers.Layer.EventPane,
23 OpenLayers.Layer.FixedZoomLevels, {
26 * Constant: MIN_ZOOM_LEVEL
32 * Constant: MAX_ZOOM_LEVEL
38 * Constant: RESOLUTIONS
39 * {Array(Float)} Hardcode these resolutions so that they are more closely
40 * tied with the standard wms projection
57 0.0000858306884765625,
58 0.00004291534423828125,
59 0.00002145767211914062,
60 0.00001072883605957031,
61 0.00000536441802978515,
62 0.00000268220901489257
72 * APIProperty: sphericalMercator
73 * {Boolean} Should the map act as a mercator-projected map? This will
74 * cause all interactions with the map to be in the actual map
75 * projection, which allows support for vector drawing, overlaying
78 sphericalMercator: false,
81 * Property: dragObject
82 * {GDraggableObject} Since 2.93, Google has exposed the ability to get
83 * the maps GDraggableObject. We can now use this for smooth panning
88 * Property: termsOfUse
89 * {DOMElement} Div for Google's copyright and terms of use link
95 * {DOMElement} Div for Google's powered by logo and link
100 * Constructor: OpenLayers.Layer.Google
103 * name - {String} A name for the layer.
104 * options - {Object} An optional object whose properties will be set
107 initialize: function(name, options) {
108 OpenLayers.Layer.EventPane.prototype.initialize.apply(this, arguments);
109 OpenLayers.Layer.FixedZoomLevels.prototype.initialize.apply(this,
111 this.addContainerPxFunction();
112 if (this.sphericalMercator) {
113 OpenLayers.Util.extend(this, OpenLayers.Layer.SphericalMercator);
114 this.initMercatorParameters();
119 * Method: loadMapObject
120 * Load the GMap and register appropriate event listeners. If we can't
121 * load GMap2, then display a warning message.
123 loadMapObject:function() {
125 //has gmaps library has been loaded?
127 // create GMap, hide nav controls
128 this.mapObject = new GMap2( this.div );
130 //since v 2.93 getDragObject is now available.
131 if(typeof this.mapObject.getDragObject == "function") {
132 this.dragObject = this.mapObject.getDragObject();
134 this.dragPanMapObject = null;
137 // move the ToS and branding stuff up to the container div
138 this.termsOfUse = this.div.lastChild;
139 this.div.removeChild(this.termsOfUse);
141 this.map.viewPortDiv.appendChild(this.termsOfUse);
143 this.map.layerContainerDiv.appendChild(this.termsOfUse);
145 this.termsOfUse.style.zIndex = "1100";
146 this.termsOfUse.style.display = this.div.style.display;
147 this.termsOfUse.style.right = "";
148 this.termsOfUse.style.bottom = "";
149 this.termsOfUse.className = "olLayerGoogleCopyright";
151 this.poweredBy = this.div.lastChild;
152 this.div.removeChild(this.poweredBy);
154 this.map.viewPortDiv.appendChild(this.poweredBy);
156 this.map.layerContainerDiv.appendChild(this.poweredBy);
158 this.poweredBy.style.zIndex = "1100";
159 this.poweredBy.style.display = this.div.style.display;
160 this.poweredBy.style.right = "";
161 this.poweredBy.style.bottom = "";
162 this.poweredBy.className = "olLayerGooglePoweredBy gmnoprint";
165 OpenLayers.Console.error(e);
172 * Overridden from EventPane because if a map type has been specified,
173 * we need to attach a listener for the first moveend -- this is how
174 * we will know that the map has been centered. Only once the map has
175 * been centered is it safe to change the gmap object's map type.
178 * map - {<OpenLayers.Map>}
180 setMap: function(map) {
181 OpenLayers.Layer.EventPane.prototype.setMap.apply(this, arguments);
183 if (this.type != null) {
184 this.map.events.register("moveend", this, this.setMapType);
190 * The map has been centered, and a map type was specified, so we
191 * set the map type on the gmap object, then unregister the listener
192 * so that we dont keep doing this every time the map moves.
194 setMapType: function() {
195 if (this.mapObject.getCenter() != null) {
197 // Support for custom map types.
198 if (OpenLayers.Util.indexOf(this.mapObject.getMapTypes(),
200 this.mapObject.addMapType(this.type);
203 this.mapObject.setMapType(this.type);
204 this.map.events.unregister("moveend", this, this.setMapType);
209 * APIMethod: onMapResize
214 onMapResize: function() {
215 // workaround for resizing of invisible or not yet fully loaded layers
216 // where GMap2.checkResize() does not work. We need to load the GMap
217 // for the old div size, then checkResize(), and then call
218 // layer.moveTo() to trigger GMap.setCenter() (which will finish
219 // the GMap initialization).
220 if(this.visibility && this.mapObject.isLoaded()) {
221 this.mapObject.checkResize();
225 var handle = GEvent.addListener(this.mapObject, "load", function() {
226 GEvent.removeListener(handle);
227 delete layer._resized;
228 layer.mapObject.checkResize();
229 layer.moveTo(layer.map.getCenter(), layer.map.getZoom());
232 this._resized = true;
238 * Hide or show the layer
241 * display - {Boolean}
243 display: function(display) {
244 OpenLayers.Layer.EventPane.prototype.display.apply(this, arguments);
245 this.termsOfUse.style.display = this.div.style.display;
246 this.poweredBy.style.display = this.div.style.display;
250 * APIMethod: removeMap
251 * On being removed from the map, also remove termsOfUse and poweredBy divs
254 * map - {<OpenLayers.Map>}
256 removeMap: function(map) {
257 if (this.termsOfUse && this.termsOfUse.parentNode) {
258 this.termsOfUse.parentNode.removeChild(this.termsOfUse);
259 this.termsOfUse = null;
261 if (this.poweredBy && this.poweredBy.parentNode) {
262 this.poweredBy.parentNode.removeChild(this.poweredBy);
263 this.poweredBy = null;
265 OpenLayers.Layer.EventPane.prototype.removeMap.apply(this, arguments);
269 * APIMethod: getZoomForExtent
272 * bounds - {<OpenLayers.Bounds>}
275 * {Integer} Corresponding zoom level for a specified Bounds.
276 * If mapObject is not loaded or not centered, returns null
278 getZoomForExtent: function (bounds) {
280 if (this.mapObject != null) {
281 var moBounds = this.getMapObjectBoundsFromOLBounds(bounds);
282 var moZoom = this.getMapObjectZoomFromMapObjectBounds(moBounds);
284 //make sure zoom is within bounds
285 var moZoom = Math.min(Math.max(moZoom, this.minZoomLevel),
288 zoom = this.getOLZoomFromMapObjectZoom(moZoom);
296 // TRANSLATION: MapObject Bounds <-> OpenLayers.Bounds
300 * APIMethod: getOLBoundsFromMapObjectBounds
303 * moBounds - {Object}
306 * {<OpenLayers.Bounds>} An <OpenLayers.Bounds>, translated from the
307 * passed-in MapObject Bounds.
308 * Returns null if null value is passed in.
310 getOLBoundsFromMapObjectBounds: function(moBounds) {
312 if (moBounds != null) {
313 var sw = moBounds.getSouthWest();
314 var ne = moBounds.getNorthEast();
315 if (this.sphericalMercator) {
316 sw = this.forwardMercator(sw.lng(), sw.lat());
317 ne = this.forwardMercator(ne.lng(), ne.lat());
319 sw = new OpenLayers.LonLat(sw.lng(), sw.lat());
320 ne = new OpenLayers.LonLat(ne.lng(), ne.lat());
322 olBounds = new OpenLayers.Bounds(sw.lon,
331 * APIMethod: getMapObjectBoundsFromOLBounds
334 * olBounds - {<OpenLayers.Bounds>}
337 * {Object} A MapObject Bounds, translated from olBounds
338 * Returns null if null value is passed in
340 getMapObjectBoundsFromOLBounds: function(olBounds) {
342 if (olBounds != null) {
343 var sw = this.sphericalMercator ?
344 this.inverseMercator(olBounds.bottom, olBounds.left) :
345 new OpenLayers.LonLat(olBounds.bottom, olBounds.left);
346 var ne = this.sphericalMercator ?
347 this.inverseMercator(olBounds.top, olBounds.right) :
348 new OpenLayers.LonLat(olBounds.top, olBounds.right);
349 moBounds = new GLatLngBounds(new GLatLng(sw.lat, sw.lon),
350 new GLatLng(ne.lat, ne.lon));
356 * Method: addContainerPxFunction
357 * Hack-on function because GMAPS does not give it to us
360 * gLatLng - {GLatLng}
363 * {GPoint} A GPoint specifying gLatLng translated into "Container" coords
365 addContainerPxFunction: function() {
366 if ( (typeof GMap2 != "undefined") &&
367 !GMap2.prototype.fromLatLngToContainerPixel) {
369 GMap2.prototype.fromLatLngToContainerPixel = function(gLatLng) {
371 // first we translate into "DivPixel"
372 var gPoint = this.fromLatLngToDivPixel(gLatLng);
374 // locate the sliding "Div" div
375 var div = this.getContainer().firstChild.firstChild;
377 // adjust by the offset of "Div" and voila!
378 gPoint.x += div.offsetLeft;
379 gPoint.y += div.offsetTop;
387 * APIMethod: getWarningHTML
390 * {String} String with information on why layer is broken, how to get
393 getWarningHTML:function() {
394 return OpenLayers.i18n("googleWarning");
398 /************************************
400 * MapObject Interface Controls *
402 ************************************/
405 // Get&Set Center, Zoom
408 * APIMethod: setMapObjectCenter
409 * Set the mapObject to the specified center and zoom
412 * center - {Object} MapObject LonLat format
413 * zoom - {int} MapObject zoom format
415 setMapObjectCenter: function(center, zoom) {
416 this.mapObject.setCenter(center, zoom);
420 * APIMethod: dragPanMapObject
426 dragPanMapObject: function(dX, dY) {
427 this.dragObject.moveBy(new GSize(-dX, dY));
431 * APIMethod: getMapObjectCenter
434 * {Object} The mapObject's current center in Map Object format
436 getMapObjectCenter: function() {
437 return this.mapObject.getCenter();
441 * APIMethod: getMapObjectZoom
444 * {Integer} The mapObject's current zoom, in Map Object format
446 getMapObjectZoom: function() {
447 return this.mapObject.getZoom();
451 // LonLat - Pixel Translation
454 * APIMethod: getMapObjectLonLatFromMapObjectPixel
457 * moPixel - {Object} MapObject Pixel format
460 * {Object} MapObject LonLat translated from MapObject Pixel
462 getMapObjectLonLatFromMapObjectPixel: function(moPixel) {
463 return this.mapObject.fromContainerPixelToLatLng(moPixel);
467 * APIMethod: getMapObjectPixelFromMapObjectLonLat
470 * moLonLat - {Object} MapObject LonLat format
473 * {Object} MapObject Pixel transtlated from MapObject LonLat
475 getMapObjectPixelFromMapObjectLonLat: function(moLonLat) {
476 return this.mapObject.fromLatLngToContainerPixel(moLonLat);
483 * APIMethod: getMapObjectZoomFromMapObjectBounds
486 * moBounds - {Object} MapObject Bounds format
489 * {Object} MapObject Zoom for specified MapObject Bounds
491 getMapObjectZoomFromMapObjectBounds: function(moBounds) {
492 return this.mapObject.getBoundsZoomLevel(moBounds);
495 /************************************
497 * MapObject Primitives *
499 ************************************/
505 * APIMethod: getLongitudeFromMapObjectLonLat
508 * moLonLat - {Object} MapObject LonLat format
511 * {Float} Longitude of the given MapObject LonLat
513 getLongitudeFromMapObjectLonLat: function(moLonLat) {
514 return this.sphericalMercator ?
515 this.forwardMercator(moLonLat.lng(), moLonLat.lat()).lon :
520 * APIMethod: getLatitudeFromMapObjectLonLat
523 * moLonLat - {Object} MapObject LonLat format
526 * {Float} Latitude of the given MapObject LonLat
528 getLatitudeFromMapObjectLonLat: function(moLonLat) {
529 var lat = this.sphericalMercator ?
530 this.forwardMercator(moLonLat.lng(), moLonLat.lat()).lat :
536 * APIMethod: getMapObjectLonLatFromLonLat
543 * {Object} MapObject LonLat built from lon and lat params
545 getMapObjectLonLatFromLonLat: function(lon, lat) {
547 if(this.sphericalMercator) {
548 var lonlat = this.inverseMercator(lon, lat);
549 gLatLng = new GLatLng(lonlat.lat, lonlat.lon);
551 gLatLng = new GLatLng(lat, lon);
559 * APIMethod: getXFromMapObjectPixel
562 * moPixel - {Object} MapObject Pixel format
565 * {Integer} X value of the MapObject Pixel
567 getXFromMapObjectPixel: function(moPixel) {
572 * APIMethod: getYFromMapObjectPixel
575 * moPixel - {Object} MapObject Pixel format
578 * {Integer} Y value of the MapObject Pixel
580 getYFromMapObjectPixel: function(moPixel) {
585 * APIMethod: getMapObjectPixelFromXY
592 * {Object} MapObject Pixel from x and y parameters
594 getMapObjectPixelFromXY: function(x, y) {
595 return new GPoint(x, y);
598 CLASS_NAME: "OpenLayers.Layer.Google"