]> dev.renevier.net Git - syp.git/blob - openlayers/lib/OpenLayers/Layer/Google.js
initial commit
[syp.git] / openlayers / lib / OpenLayers / Layer / Google.js
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. */
4
5
6 /**
7  * @requires OpenLayers/Layer/SphericalMercator.js
8  * @requires OpenLayers/Layer/EventPane.js
9  * @requires OpenLayers/Layer/FixedZoomLevels.js
10  * @requires OpenLayers/Console.js
11  */
12
13 /**
14  * Class: OpenLayers.Layer.Google
15  * 
16  * Inherits from:
17  *  - <OpenLayers.Layer.SphericalMercator>
18  *  - <OpenLayers.Layer.EventPane>
19  *  - <OpenLayers.Layer.FixedZoomLevels>
20  */
21 OpenLayers.Layer.Google = OpenLayers.Class(
22     OpenLayers.Layer.EventPane, 
23     OpenLayers.Layer.FixedZoomLevels, {
24     
25     /** 
26      * Constant: MIN_ZOOM_LEVEL
27      * {Integer} 0 
28      */
29     MIN_ZOOM_LEVEL: 0,
30     
31     /** 
32      * Constant: MAX_ZOOM_LEVEL
33      * {Integer} 19
34      */
35     MAX_ZOOM_LEVEL: 19,
36
37     /** 
38      * Constant: RESOLUTIONS
39      * {Array(Float)} Hardcode these resolutions so that they are more closely
40      *                tied with the standard wms projection
41      */
42     RESOLUTIONS: [
43         1.40625, 
44         0.703125, 
45         0.3515625, 
46         0.17578125, 
47         0.087890625, 
48         0.0439453125,
49         0.02197265625, 
50         0.010986328125, 
51         0.0054931640625, 
52         0.00274658203125,
53         0.001373291015625, 
54         0.0006866455078125, 
55         0.00034332275390625,
56         0.000171661376953125, 
57         0.0000858306884765625, 
58         0.00004291534423828125,
59         0.00002145767211914062, 
60         0.00001072883605957031,
61         0.00000536441802978515, 
62         0.00000268220901489257
63     ],
64
65     /**
66      * APIProperty: type
67      * {GMapType}
68      */
69     type: null,
70
71     /**
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 
76      *     other maps, etc. 
77      */
78     sphericalMercator: false, 
79     
80     /**
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
84      */
85     dragObject: null, 
86
87     /**
88      * Property: termsOfUse
89      * {DOMElement} Div for Google's copyright and terms of use link
90      */
91     termsOfUse: null, 
92
93     /**
94      * Property: poweredBy
95      * {DOMElement} Div for Google's powered by logo and link
96      */
97     poweredBy: null, 
98
99     /** 
100      * Constructor: OpenLayers.Layer.Google
101      * 
102      * Parameters:
103      * name - {String} A name for the layer.
104      * options - {Object} An optional object whose properties will be set
105      *     on the layer.
106      */
107     initialize: function(name, options) {
108         OpenLayers.Layer.EventPane.prototype.initialize.apply(this, arguments);
109         OpenLayers.Layer.FixedZoomLevels.prototype.initialize.apply(this, 
110                                                                     arguments);
111         this.addContainerPxFunction();
112         if (this.sphericalMercator) {
113             OpenLayers.Util.extend(this, OpenLayers.Layer.SphericalMercator);
114             this.initMercatorParameters();
115         }    
116     },
117     
118     /** 
119      * Method: loadMapObject
120      * Load the GMap and register appropriate event listeners. If we can't 
121      *     load GMap2, then display a warning message.
122      */
123     loadMapObject:function() {
124         
125         //has gmaps library has been loaded?
126         try {
127             // create GMap, hide nav controls
128             this.mapObject = new GMap2( this.div );
129             
130             //since v 2.93 getDragObject is now available.
131             if(typeof this.mapObject.getDragObject == "function") {
132                 this.dragObject = this.mapObject.getDragObject();
133             } else {
134                 this.dragPanMapObject = null;
135             }
136
137             // move the ToS and branding stuff up to the container div
138             this.termsOfUse = this.div.lastChild;
139             this.div.removeChild(this.termsOfUse);
140             if (this.isFixed) {
141                 this.map.viewPortDiv.appendChild(this.termsOfUse);
142             } else {
143                 this.map.layerContainerDiv.appendChild(this.termsOfUse);
144             }
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";
150
151             this.poweredBy = this.div.lastChild;
152             this.div.removeChild(this.poweredBy);
153             if (this.isFixed) {
154                 this.map.viewPortDiv.appendChild(this.poweredBy);
155             } else {
156                 this.map.layerContainerDiv.appendChild(this.poweredBy);
157             }
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"; 
163
164         } catch (e) {
165             OpenLayers.Console.error(e);
166         }
167                
168     },
169
170     /** 
171      * APIMethod: setMap
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. 
176      * 
177      * Parameters:
178      * map - {<OpenLayers.Map>}
179      */
180     setMap: function(map) {
181         OpenLayers.Layer.EventPane.prototype.setMap.apply(this, arguments);
182
183         if (this.type != null) {
184             this.map.events.register("moveend", this, this.setMapType);
185         }
186     },
187     
188     /** 
189      * Method: 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.
193      */
194     setMapType: function() {
195         if (this.mapObject.getCenter() != null) {
196             
197             // Support for custom map types.
198             if (OpenLayers.Util.indexOf(this.mapObject.getMapTypes(),
199                                         this.type) == -1) {
200                 this.mapObject.addMapType(this.type);
201             }    
202
203             this.mapObject.setMapType(this.type);
204             this.map.events.unregister("moveend", this, this.setMapType);
205         }
206     },
207
208     /**
209      * APIMethod: onMapResize
210      * 
211      * Parameters:
212      * evt - {Event}
213      */
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();
222         } else {
223             if(!this._resized) {
224                 var layer = this;
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());
230                 })
231             }
232             this._resized = true;
233         }
234     },
235
236     /**
237      * Method: display
238      * Hide or show the layer
239      *
240      * Parameters:
241      * display - {Boolean}
242      */
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;
247     },
248
249     /**
250      * APIMethod: removeMap
251      * On being removed from the map, also remove termsOfUse and poweredBy divs
252      * 
253      * Parameters:
254      * map - {<OpenLayers.Map>}
255      */
256     removeMap: function(map) {
257         if (this.termsOfUse && this.termsOfUse.parentNode) {
258             this.termsOfUse.parentNode.removeChild(this.termsOfUse);
259             this.termsOfUse = null;
260         }
261         if (this.poweredBy && this.poweredBy.parentNode) {
262             this.poweredBy.parentNode.removeChild(this.poweredBy);
263             this.poweredBy = null;
264         }
265         OpenLayers.Layer.EventPane.prototype.removeMap.apply(this, arguments);
266     },
267     
268     /**
269      * APIMethod: getZoomForExtent
270      * 
271      * Parameters:
272      * bounds - {<OpenLayers.Bounds>}
273      *  
274      * Returns:
275      * {Integer} Corresponding zoom level for a specified Bounds. 
276      *           If mapObject is not loaded or not centered, returns null
277      *
278     getZoomForExtent: function (bounds) {
279         var zoom = null;
280         if (this.mapObject != null) {
281             var moBounds = this.getMapObjectBoundsFromOLBounds(bounds);
282             var moZoom = this.getMapObjectZoomFromMapObjectBounds(moBounds);
283
284             //make sure zoom is within bounds    
285             var moZoom = Math.min(Math.max(moZoom, this.minZoomLevel), 
286                                  this.maxZoomLevel);
287
288             zoom = this.getOLZoomFromMapObjectZoom(moZoom);
289         }
290         return zoom;
291     },
292     
293     */
294     
295   //
296   // TRANSLATION: MapObject Bounds <-> OpenLayers.Bounds
297   //
298
299     /**
300      * APIMethod: getOLBoundsFromMapObjectBounds
301      * 
302      * Parameters:
303      * moBounds - {Object}
304      * 
305      * Returns:
306      * {<OpenLayers.Bounds>} An <OpenLayers.Bounds>, translated from the 
307      *                       passed-in MapObject Bounds.
308      *                       Returns null if null value is passed in.
309      */
310     getOLBoundsFromMapObjectBounds: function(moBounds) {
311         var olBounds = null;
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());
318             } else {
319                 sw = new OpenLayers.LonLat(sw.lng(), sw.lat()); 
320                 ne = new OpenLayers.LonLat(ne.lng(), ne.lat()); 
321             }    
322             olBounds = new OpenLayers.Bounds(sw.lon, 
323                                              sw.lat, 
324                                              ne.lon, 
325                                              ne.lat );
326         }
327         return olBounds;
328     },
329
330     /**
331      * APIMethod: getMapObjectBoundsFromOLBounds
332      * 
333      * Parameters:
334      * olBounds - {<OpenLayers.Bounds>}
335      * 
336      * Returns:
337      * {Object} A MapObject Bounds, translated from olBounds
338      *          Returns null if null value is passed in
339      */
340     getMapObjectBoundsFromOLBounds: function(olBounds) {
341         var moBounds = null;
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));
351         }
352         return moBounds;
353     },
354
355     /** 
356      * Method: addContainerPxFunction
357      * Hack-on function because GMAPS does not give it to us
358      * 
359      * Parameters: 
360      * gLatLng - {GLatLng}
361      * 
362      * Returns:
363      * {GPoint} A GPoint specifying gLatLng translated into "Container" coords
364      */
365     addContainerPxFunction: function() {
366         if ( (typeof GMap2 != "undefined") && 
367              !GMap2.prototype.fromLatLngToContainerPixel) {
368           
369             GMap2.prototype.fromLatLngToContainerPixel = function(gLatLng) {
370           
371                 // first we translate into "DivPixel"
372                 var gPoint = this.fromLatLngToDivPixel(gLatLng);
373       
374                 // locate the sliding "Div" div
375                 var div = this.getContainer().firstChild.firstChild;
376   
377                 // adjust by the offset of "Div" and voila!
378                 gPoint.x += div.offsetLeft;
379                 gPoint.y += div.offsetTop;
380     
381                 return gPoint;
382             };
383         }
384     },
385
386     /** 
387      * APIMethod: getWarningHTML
388      * 
389      * Returns: 
390      * {String} String with information on why layer is broken, how to get
391      *          it working.
392      */
393     getWarningHTML:function() {
394         return OpenLayers.i18n("googleWarning");
395     },
396
397
398     /************************************
399      *                                  *
400      *   MapObject Interface Controls   *
401      *                                  *
402      ************************************/
403
404
405   // Get&Set Center, Zoom
406
407     /** 
408      * APIMethod: setMapObjectCenter
409      * Set the mapObject to the specified center and zoom
410      * 
411      * Parameters:
412      * center - {Object} MapObject LonLat format
413      * zoom - {int} MapObject zoom format
414      */
415     setMapObjectCenter: function(center, zoom) {
416         this.mapObject.setCenter(center, zoom); 
417     },
418    
419     /**
420      * APIMethod: dragPanMapObject
421      * 
422      * Parameters:
423      * dX - {Integer}
424      * dY - {Integer}
425      */
426     dragPanMapObject: function(dX, dY) {
427         this.dragObject.moveBy(new GSize(-dX, dY));
428     },
429
430     /**
431      * APIMethod: getMapObjectCenter
432      * 
433      * Returns: 
434      * {Object} The mapObject's current center in Map Object format
435      */
436     getMapObjectCenter: function() {
437         return this.mapObject.getCenter();
438     },
439
440     /** 
441      * APIMethod: getMapObjectZoom
442      * 
443      * Returns:
444      * {Integer} The mapObject's current zoom, in Map Object format
445      */
446     getMapObjectZoom: function() {
447         return this.mapObject.getZoom();
448     },
449
450
451   // LonLat - Pixel Translation
452   
453     /**
454      * APIMethod: getMapObjectLonLatFromMapObjectPixel
455      * 
456      * Parameters:
457      * moPixel - {Object} MapObject Pixel format
458      * 
459      * Returns:
460      * {Object} MapObject LonLat translated from MapObject Pixel
461      */
462     getMapObjectLonLatFromMapObjectPixel: function(moPixel) {
463         return this.mapObject.fromContainerPixelToLatLng(moPixel);
464     },
465
466     /**
467      * APIMethod: getMapObjectPixelFromMapObjectLonLat
468      * 
469      * Parameters:
470      * moLonLat - {Object} MapObject LonLat format
471      * 
472      * Returns:
473      * {Object} MapObject Pixel transtlated from MapObject LonLat
474      */
475     getMapObjectPixelFromMapObjectLonLat: function(moLonLat) {
476         return this.mapObject.fromLatLngToContainerPixel(moLonLat);
477     },
478
479   
480   // Bounds
481   
482     /** 
483      * APIMethod: getMapObjectZoomFromMapObjectBounds
484      * 
485      * Parameters:
486      * moBounds - {Object} MapObject Bounds format
487      * 
488      * Returns:
489      * {Object} MapObject Zoom for specified MapObject Bounds
490      */
491     getMapObjectZoomFromMapObjectBounds: function(moBounds) {
492         return this.mapObject.getBoundsZoomLevel(moBounds);
493     },
494
495     /************************************
496      *                                  *
497      *       MapObject Primitives       *
498      *                                  *
499      ************************************/
500
501
502   // LonLat
503     
504     /**
505      * APIMethod: getLongitudeFromMapObjectLonLat
506      * 
507      * Parameters:
508      * moLonLat - {Object} MapObject LonLat format
509      * 
510      * Returns:
511      * {Float} Longitude of the given MapObject LonLat
512      */
513     getLongitudeFromMapObjectLonLat: function(moLonLat) {
514         return this.sphericalMercator ? 
515           this.forwardMercator(moLonLat.lng(), moLonLat.lat()).lon :
516           moLonLat.lng();  
517     },
518
519     /**
520      * APIMethod: getLatitudeFromMapObjectLonLat
521      * 
522      * Parameters:
523      * moLonLat - {Object} MapObject LonLat format
524      * 
525      * Returns:
526      * {Float} Latitude of the given MapObject LonLat
527      */
528     getLatitudeFromMapObjectLonLat: function(moLonLat) {
529         var lat = this.sphericalMercator ? 
530           this.forwardMercator(moLonLat.lng(), moLonLat.lat()).lat :
531           moLonLat.lat(); 
532         return lat;  
533     },
534     
535     /**
536      * APIMethod: getMapObjectLonLatFromLonLat
537      * 
538      * Parameters:
539      * lon - {Float}
540      * lat - {Float}
541      * 
542      * Returns:
543      * {Object} MapObject LonLat built from lon and lat params
544      */
545     getMapObjectLonLatFromLonLat: function(lon, lat) {
546         var gLatLng;
547         if(this.sphericalMercator) {
548             var lonlat = this.inverseMercator(lon, lat);
549             gLatLng = new GLatLng(lonlat.lat, lonlat.lon);
550         } else {
551             gLatLng = new GLatLng(lat, lon);
552         }
553         return gLatLng;
554     },
555
556   // Pixel
557     
558     /**
559      * APIMethod: getXFromMapObjectPixel
560      * 
561      * Parameters:
562      * moPixel - {Object} MapObject Pixel format
563      * 
564      * Returns:
565      * {Integer} X value of the MapObject Pixel
566      */
567     getXFromMapObjectPixel: function(moPixel) {
568         return moPixel.x;
569     },
570
571     /**
572      * APIMethod: getYFromMapObjectPixel
573      * 
574      * Parameters:
575      * moPixel - {Object} MapObject Pixel format
576      * 
577      * Returns:
578      * {Integer} Y value of the MapObject Pixel
579      */
580     getYFromMapObjectPixel: function(moPixel) {
581         return moPixel.y;
582     },
583
584     /**
585      * APIMethod: getMapObjectPixelFromXY
586      * 
587      * Parameters:
588      * x - {Integer}
589      * y - {Integer}
590      * 
591      * Returns:
592      * {Object} MapObject Pixel from x and y parameters
593      */
594     getMapObjectPixelFromXY: function(x, y) {
595         return new GPoint(x, y);
596     },
597
598     CLASS_NAME: "OpenLayers.Layer.Google"
599 });