[76] | 1 | /* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for |
---|
| 2 | * full list of contributors). Published under the Clear BSD license. |
---|
| 3 | * See http://svn.openlayers.org/trunk/openlayers/license.txt for the |
---|
| 4 | * full text of the license. */ |
---|
| 5 | |
---|
| 6 | |
---|
| 7 | /** |
---|
| 8 | * @requires OpenLayers/Layer/Google.js |
---|
| 9 | */ |
---|
| 10 | |
---|
| 11 | /** |
---|
| 12 | * Constant: OpenLayers.Layer.Google.v3 |
---|
| 13 | * |
---|
| 14 | * Mixin providing functionality specific to the Google Maps API v3. Note that |
---|
| 15 | * this layer configures the google.maps.map object with the "disableDefaultUI" |
---|
| 16 | * option set to true. Using UI controls that the Google Maps API provides is |
---|
| 17 | * not supported by the OpenLayers API. |
---|
| 18 | */ |
---|
| 19 | OpenLayers.Layer.Google.v3 = { |
---|
| 20 | |
---|
| 21 | /** |
---|
| 22 | * Constant: DEFAULTS |
---|
| 23 | * {Object} It is not recommended to change the properties set here. Note |
---|
| 24 | * that Google.v3 layers only work when sphericalMercator is set to true. |
---|
| 25 | * |
---|
| 26 | * (code) |
---|
| 27 | * { |
---|
| 28 | * maxExtent: new OpenLayers.Bounds( |
---|
| 29 | * -128 * 156543.0339, |
---|
| 30 | * -128 * 156543.0339, |
---|
| 31 | * 128 * 156543.0339, |
---|
| 32 | * 128 * 156543.0339 |
---|
| 33 | * ), |
---|
| 34 | * sphericalMercator: true, |
---|
| 35 | * maxResolution: 156543.0339, |
---|
| 36 | * units: "m", |
---|
| 37 | * projection: "EPSG:900913" |
---|
| 38 | * } |
---|
| 39 | * (end) |
---|
| 40 | */ |
---|
| 41 | DEFAULTS: { |
---|
| 42 | maxExtent: new OpenLayers.Bounds( |
---|
| 43 | -128 * 156543.0339, |
---|
| 44 | -128 * 156543.0339, |
---|
| 45 | 128 * 156543.0339, |
---|
| 46 | 128 * 156543.0339 |
---|
| 47 | ), |
---|
| 48 | sphericalMercator: true, |
---|
| 49 | maxResolution: 156543.0339, |
---|
| 50 | units: "m", |
---|
| 51 | projection: "EPSG:900913" |
---|
| 52 | }, |
---|
| 53 | |
---|
| 54 | /** |
---|
| 55 | * Method: loadMapObject |
---|
| 56 | * Load the GMap and register appropriate event listeners. If we can't |
---|
| 57 | * load GMap2, then display a warning message. |
---|
| 58 | */ |
---|
| 59 | loadMapObject:function() { |
---|
| 60 | if (!this.type) { |
---|
| 61 | this.type = google.maps.MapTypeId.ROADMAP; |
---|
| 62 | } |
---|
| 63 | var mapObject; |
---|
| 64 | var cache = OpenLayers.Layer.Google.cache[this.map.id]; |
---|
| 65 | if (cache) { |
---|
| 66 | // there are already Google layers added to this map |
---|
| 67 | mapObject = cache.mapObject; |
---|
| 68 | // increment the layer count |
---|
| 69 | ++cache.count; |
---|
| 70 | } else { |
---|
| 71 | // this is the first Google layer for this map |
---|
| 72 | |
---|
| 73 | var container = this.map.viewPortDiv; |
---|
| 74 | var div = document.createElement("div"); |
---|
| 75 | div.id = this.map.id + "_GMapContainer"; |
---|
| 76 | div.style.position = "absolute"; |
---|
| 77 | div.style.width = "100%"; |
---|
| 78 | div.style.height = "100%"; |
---|
| 79 | container.appendChild(div); |
---|
| 80 | |
---|
| 81 | // create GMap and shuffle elements |
---|
| 82 | var center = this.map.getCenter(); |
---|
| 83 | mapObject = new google.maps.Map(div, { |
---|
| 84 | center: center ? |
---|
| 85 | new google.maps.LatLng(center.lat, center.lon) : |
---|
| 86 | new google.maps.LatLng(0, 0), |
---|
| 87 | zoom: this.map.getZoom() || 0, |
---|
| 88 | mapTypeId: this.type, |
---|
| 89 | disableDefaultUI: true, |
---|
| 90 | keyboardShortcuts: false, |
---|
| 91 | draggable: false, |
---|
| 92 | disableDoubleClickZoom: true, |
---|
| 93 | scrollwheel: false |
---|
| 94 | }); |
---|
| 95 | |
---|
| 96 | // cache elements for use by any other google layers added to |
---|
| 97 | // this same map |
---|
| 98 | cache = { |
---|
| 99 | mapObject: mapObject, |
---|
| 100 | count: 1 |
---|
| 101 | }; |
---|
| 102 | OpenLayers.Layer.Google.cache[this.map.id] = cache; |
---|
| 103 | this.repositionListener = google.maps.event.addListenerOnce( |
---|
| 104 | mapObject, |
---|
| 105 | "center_changed", |
---|
| 106 | OpenLayers.Function.bind(this.repositionMapElements, this) |
---|
| 107 | ); |
---|
| 108 | } |
---|
| 109 | this.mapObject = mapObject; |
---|
| 110 | this.setGMapVisibility(this.visibility); |
---|
| 111 | }, |
---|
| 112 | |
---|
| 113 | /** |
---|
| 114 | * Method: repositionMapElements |
---|
| 115 | * |
---|
| 116 | * Waits until powered by and terms of use elements are available and then |
---|
| 117 | * moves them so they are clickable. |
---|
| 118 | */ |
---|
| 119 | repositionMapElements: function() { |
---|
| 120 | |
---|
| 121 | // This is the first time any Google layer in this mapObject has been |
---|
| 122 | // made visible. The mapObject needs to know the container size. |
---|
| 123 | google.maps.event.trigger(this.mapObject, "resize"); |
---|
| 124 | |
---|
| 125 | var div = this.mapObject.getDiv().firstChild; |
---|
| 126 | if (!div || div.childNodes.length < 3) { |
---|
| 127 | this.repositionTimer = window.setTimeout( |
---|
| 128 | OpenLayers.Function.bind(this.repositionMapElements, this), |
---|
| 129 | 250 |
---|
| 130 | ); |
---|
| 131 | return false; |
---|
| 132 | } |
---|
| 133 | |
---|
| 134 | var cache = OpenLayers.Layer.Google.cache[this.map.id]; |
---|
| 135 | var container = this.map.viewPortDiv; |
---|
| 136 | |
---|
| 137 | // move the ToS and branding stuff up to the container div |
---|
| 138 | var termsOfUse = div.lastChild; |
---|
| 139 | container.appendChild(termsOfUse); |
---|
| 140 | termsOfUse.style.zIndex = "1100"; |
---|
| 141 | termsOfUse.style.bottom = ""; |
---|
| 142 | termsOfUse.className = "olLayerGoogleCopyright olLayerGoogleV3"; |
---|
| 143 | termsOfUse.style.display = ""; |
---|
| 144 | cache.termsOfUse = termsOfUse; |
---|
| 145 | |
---|
| 146 | var poweredBy = div.lastChild; |
---|
| 147 | container.appendChild(poweredBy); |
---|
| 148 | poweredBy.style.zIndex = "1100"; |
---|
| 149 | poweredBy.style.bottom = ""; |
---|
| 150 | poweredBy.className = "olLayerGooglePoweredBy olLayerGoogleV3 gmnoprint"; |
---|
| 151 | poweredBy.style.display = ""; |
---|
| 152 | cache.poweredBy = poweredBy; |
---|
| 153 | |
---|
| 154 | this.setGMapVisibility(this.visibility); |
---|
| 155 | |
---|
| 156 | }, |
---|
| 157 | |
---|
| 158 | /** |
---|
| 159 | * APIMethod: onMapResize |
---|
| 160 | */ |
---|
| 161 | onMapResize: function() { |
---|
| 162 | if (this.visibility) { |
---|
| 163 | google.maps.event.trigger(this.mapObject, "resize"); |
---|
| 164 | } else { |
---|
| 165 | if (!this._resized) { |
---|
| 166 | var layer = this; |
---|
| 167 | google.maps.event.addListenerOnce(this.mapObject, "tilesloaded", function() { |
---|
| 168 | delete layer._resized; |
---|
| 169 | google.maps.event.trigger(layer.mapObject, "resize"); |
---|
| 170 | layer.moveTo(layer.map.getCenter(), layer.map.getZoom()); |
---|
| 171 | }); |
---|
| 172 | } |
---|
| 173 | this._resized = true; |
---|
| 174 | } |
---|
| 175 | }, |
---|
| 176 | |
---|
| 177 | /** |
---|
| 178 | * Method: setGMapVisibility |
---|
| 179 | * Display the GMap container and associated elements. |
---|
| 180 | * |
---|
| 181 | * Parameters: |
---|
| 182 | * visible - {Boolean} Display the GMap elements. |
---|
| 183 | */ |
---|
| 184 | setGMapVisibility: function(visible) { |
---|
| 185 | var cache = OpenLayers.Layer.Google.cache[this.map.id]; |
---|
| 186 | if (cache) { |
---|
| 187 | var type = this.type; |
---|
| 188 | var layers = this.map.layers; |
---|
| 189 | var layer; |
---|
| 190 | for (var i=layers.length-1; i>=0; --i) { |
---|
| 191 | layer = layers[i]; |
---|
| 192 | if (layer instanceof OpenLayers.Layer.Google && |
---|
| 193 | layer.visibility === true && layer.inRange === true) { |
---|
| 194 | type = layer.type; |
---|
| 195 | visible = true; |
---|
| 196 | break; |
---|
| 197 | } |
---|
| 198 | } |
---|
| 199 | var container = this.mapObject.getDiv(); |
---|
| 200 | if (visible === true) { |
---|
| 201 | this.mapObject.setMapTypeId(type); |
---|
| 202 | container.style.left = ""; |
---|
| 203 | if (cache.termsOfUse && cache.termsOfUse.style) { |
---|
| 204 | cache.termsOfUse.style.left = ""; |
---|
| 205 | cache.termsOfUse.style.display = ""; |
---|
| 206 | cache.poweredBy.style.display = ""; |
---|
| 207 | } |
---|
| 208 | cache.displayed = this.id; |
---|
| 209 | } else { |
---|
| 210 | delete cache.displayed; |
---|
| 211 | container.style.left = "-9999px"; |
---|
| 212 | if (cache.termsOfUse && cache.termsOfUse.style) { |
---|
| 213 | cache.termsOfUse.style.display = "none"; |
---|
| 214 | // move ToU far to the left in addition to setting |
---|
| 215 | // display to "none", because at the end of the GMap |
---|
| 216 | // load sequence, display: none will be unset and ToU |
---|
| 217 | // would be visible after loading a map with a google |
---|
| 218 | // layer that is initially hidden. |
---|
| 219 | cache.termsOfUse.style.left = "-9999px"; |
---|
| 220 | cache.poweredBy.style.display = "none"; |
---|
| 221 | } |
---|
| 222 | } |
---|
| 223 | } |
---|
| 224 | }, |
---|
| 225 | |
---|
| 226 | /** |
---|
| 227 | * Method: getMapContainer |
---|
| 228 | * |
---|
| 229 | * Returns: |
---|
| 230 | * {DOMElement} the GMap container's div |
---|
| 231 | */ |
---|
| 232 | getMapContainer: function() { |
---|
| 233 | return this.mapObject.getDiv(); |
---|
| 234 | }, |
---|
| 235 | |
---|
| 236 | // |
---|
| 237 | // TRANSLATION: MapObject Bounds <-> OpenLayers.Bounds |
---|
| 238 | // |
---|
| 239 | |
---|
| 240 | /** |
---|
| 241 | * APIMethod: getMapObjectBoundsFromOLBounds |
---|
| 242 | * |
---|
| 243 | * Parameters: |
---|
| 244 | * olBounds - {<OpenLayers.Bounds>} |
---|
| 245 | * |
---|
| 246 | * Returns: |
---|
| 247 | * {Object} A MapObject Bounds, translated from olBounds |
---|
| 248 | * Returns null if null value is passed in |
---|
| 249 | */ |
---|
| 250 | getMapObjectBoundsFromOLBounds: function(olBounds) { |
---|
| 251 | var moBounds = null; |
---|
| 252 | if (olBounds != null) { |
---|
| 253 | var sw = this.sphericalMercator ? |
---|
| 254 | this.inverseMercator(olBounds.bottom, olBounds.left) : |
---|
| 255 | new OpenLayers.LonLat(olBounds.bottom, olBounds.left); |
---|
| 256 | var ne = this.sphericalMercator ? |
---|
| 257 | this.inverseMercator(olBounds.top, olBounds.right) : |
---|
| 258 | new OpenLayers.LonLat(olBounds.top, olBounds.right); |
---|
| 259 | moBounds = new google.maps.LatLngBounds( |
---|
| 260 | new google.maps.LatLng(sw.lat, sw.lon), |
---|
| 261 | new google.maps.LatLng(ne.lat, ne.lon) |
---|
| 262 | ); |
---|
| 263 | } |
---|
| 264 | return moBounds; |
---|
| 265 | }, |
---|
| 266 | |
---|
| 267 | |
---|
| 268 | /************************************ |
---|
| 269 | * * |
---|
| 270 | * MapObject Interface Controls * |
---|
| 271 | * * |
---|
| 272 | ************************************/ |
---|
| 273 | |
---|
| 274 | |
---|
| 275 | // LonLat - Pixel Translation |
---|
| 276 | |
---|
| 277 | /** |
---|
| 278 | * APIMethod: getMapObjectLonLatFromMapObjectPixel |
---|
| 279 | * |
---|
| 280 | * Parameters: |
---|
| 281 | * moPixel - {Object} MapObject Pixel format |
---|
| 282 | * |
---|
| 283 | * Returns: |
---|
| 284 | * {Object} MapObject LonLat translated from MapObject Pixel |
---|
| 285 | */ |
---|
| 286 | getMapObjectLonLatFromMapObjectPixel: function(moPixel) { |
---|
| 287 | var size = this.map.getSize(); |
---|
| 288 | var lon = this.getLongitudeFromMapObjectLonLat(this.mapObject.center); |
---|
| 289 | var lat = this.getLatitudeFromMapObjectLonLat(this.mapObject.center); |
---|
| 290 | var res = this.map.getResolution(); |
---|
| 291 | |
---|
| 292 | var delta_x = moPixel.x - (size.w / 2); |
---|
| 293 | var delta_y = moPixel.y - (size.h / 2); |
---|
| 294 | |
---|
| 295 | var lonlat = new OpenLayers.LonLat( |
---|
| 296 | lon + delta_x * res, |
---|
| 297 | lat - delta_y * res |
---|
| 298 | ); |
---|
| 299 | |
---|
| 300 | if (this.wrapDateLine) { |
---|
| 301 | lonlat = lonlat.wrapDateLine(this.maxExtent); |
---|
| 302 | } |
---|
| 303 | return this.getMapObjectLonLatFromLonLat(lonlat.lon, lonlat.lat); |
---|
| 304 | }, |
---|
| 305 | |
---|
| 306 | /** |
---|
| 307 | * APIMethod: getMapObjectPixelFromMapObjectLonLat |
---|
| 308 | * |
---|
| 309 | * Parameters: |
---|
| 310 | * moLonLat - {Object} MapObject LonLat format |
---|
| 311 | * |
---|
| 312 | * Returns: |
---|
| 313 | * {Object} MapObject Pixel transtlated from MapObject LonLat |
---|
| 314 | */ |
---|
| 315 | getMapObjectPixelFromMapObjectLonLat: function(moLonLat) { |
---|
| 316 | var lon = this.getLongitudeFromMapObjectLonLat(moLonLat); |
---|
| 317 | var lat = this.getLatitudeFromMapObjectLonLat(moLonLat); |
---|
| 318 | var res = this.map.getResolution(); |
---|
| 319 | var extent = this.map.getExtent(); |
---|
| 320 | var px = new OpenLayers.Pixel( |
---|
| 321 | (1/res * (lon - extent.left)), |
---|
| 322 | (1/res * (extent.top - lat)) |
---|
| 323 | ); |
---|
| 324 | return this.getMapObjectPixelFromXY(px.x, px.y); |
---|
| 325 | }, |
---|
| 326 | |
---|
| 327 | |
---|
| 328 | /** |
---|
| 329 | * APIMethod: setMapObjectCenter |
---|
| 330 | * Set the mapObject to the specified center and zoom |
---|
| 331 | * |
---|
| 332 | * Parameters: |
---|
| 333 | * center - {Object} MapObject LonLat format |
---|
| 334 | * zoom - {int} MapObject zoom format |
---|
| 335 | */ |
---|
| 336 | setMapObjectCenter: function(center, zoom) { |
---|
| 337 | this.mapObject.setOptions({ |
---|
| 338 | center: center, |
---|
| 339 | zoom: zoom |
---|
| 340 | }); |
---|
| 341 | }, |
---|
| 342 | |
---|
| 343 | |
---|
| 344 | // Bounds |
---|
| 345 | |
---|
| 346 | /** |
---|
| 347 | * APIMethod: getMapObjectZoomFromMapObjectBounds |
---|
| 348 | * |
---|
| 349 | * Parameters: |
---|
| 350 | * moBounds - {Object} MapObject Bounds format |
---|
| 351 | * |
---|
| 352 | * Returns: |
---|
| 353 | * {Object} MapObject Zoom for specified MapObject Bounds |
---|
| 354 | */ |
---|
| 355 | getMapObjectZoomFromMapObjectBounds: function(moBounds) { |
---|
| 356 | return this.mapObject.getBoundsZoomLevel(moBounds); |
---|
| 357 | }, |
---|
| 358 | |
---|
| 359 | /************************************ |
---|
| 360 | * * |
---|
| 361 | * MapObject Primitives * |
---|
| 362 | * * |
---|
| 363 | ************************************/ |
---|
| 364 | |
---|
| 365 | |
---|
| 366 | // LonLat |
---|
| 367 | |
---|
| 368 | /** |
---|
| 369 | * APIMethod: getMapObjectLonLatFromLonLat |
---|
| 370 | * |
---|
| 371 | * Parameters: |
---|
| 372 | * lon - {Float} |
---|
| 373 | * lat - {Float} |
---|
| 374 | * |
---|
| 375 | * Returns: |
---|
| 376 | * {Object} MapObject LonLat built from lon and lat params |
---|
| 377 | */ |
---|
| 378 | getMapObjectLonLatFromLonLat: function(lon, lat) { |
---|
| 379 | var gLatLng; |
---|
| 380 | if(this.sphericalMercator) { |
---|
| 381 | var lonlat = this.inverseMercator(lon, lat); |
---|
| 382 | gLatLng = new google.maps.LatLng(lonlat.lat, lonlat.lon); |
---|
| 383 | } else { |
---|
| 384 | gLatLng = new google.maps.LatLng(lat, lon); |
---|
| 385 | } |
---|
| 386 | return gLatLng; |
---|
| 387 | }, |
---|
| 388 | |
---|
| 389 | // Pixel |
---|
| 390 | |
---|
| 391 | /** |
---|
| 392 | * APIMethod: getMapObjectPixelFromXY |
---|
| 393 | * |
---|
| 394 | * Parameters: |
---|
| 395 | * x - {Integer} |
---|
| 396 | * y - {Integer} |
---|
| 397 | * |
---|
| 398 | * Returns: |
---|
| 399 | * {Object} MapObject Pixel from x and y parameters |
---|
| 400 | */ |
---|
| 401 | getMapObjectPixelFromXY: function(x, y) { |
---|
| 402 | return new google.maps.Point(x, y); |
---|
| 403 | }, |
---|
| 404 | |
---|
| 405 | /** |
---|
| 406 | * APIMethod: destroy |
---|
| 407 | * Clean up this layer. |
---|
| 408 | */ |
---|
| 409 | destroy: function() { |
---|
| 410 | if (this.repositionListener) { |
---|
| 411 | google.maps.event.removeListener(this.repositionListener); |
---|
| 412 | } |
---|
| 413 | if (this.repositionTimer) { |
---|
| 414 | window.clearTimeout(this.repositionTimer); |
---|
| 415 | } |
---|
| 416 | OpenLayers.Layer.Google.prototype.destroy.apply(this, arguments); |
---|
| 417 | } |
---|
| 418 | |
---|
| 419 | }; |
---|