diff --git a/examples/google-v3.html b/examples/google-v3.html index 4365dafbf8..5c11ae9312 100644 --- a/examples/google-v3.html +++ b/examples/google-v3.html @@ -6,7 +6,6 @@ OpenLayers Google (v3) Layer Example - @@ -30,21 +29,6 @@ spherical mercator projection. See the google-v3.js source to see how this is done. -

- In order to position the Google attribution div in the default - location, you must include the extra theme/default/google.css - stylesheet. -

-

- Note on Google Maps API versioning: - This example uses the "nightly" version of Google Maps - API. This is specified by using v=3 in the - the Google Maps API URL. Production applications should use the - "release" or "frozen" versions of Google Maps - API. See the OpenLayers.Layer.Google.v3 API - docs, and the - Versioning Section - of the Google Maps API docs, for more details.

diff --git a/examples/google-v3.js b/examples/google-v3.js index 4d4cd205df..e81c6a4c22 100644 --- a/examples/google-v3.js +++ b/examples/google-v3.js @@ -1,35 +1,34 @@ var map; function init() { - map = new OpenLayers.Map('map'); + map = new OpenLayers.Map('map', { + projection: 'EPSG:3857', + layers: [ + new OpenLayers.Layer.Google( + "Google Physical", + {type: google.maps.MapTypeId.TERRAIN} + ), + new OpenLayers.Layer.Google( + "Google Streets", // the default + {numZoomLevels: 20} + ), + new OpenLayers.Layer.Google( + "Google Hybrid", + {type: google.maps.MapTypeId.HYBRID, numZoomLevels: 20} + ), + new OpenLayers.Layer.Google( + "Google Satellite", + {type: google.maps.MapTypeId.SATELLITE, numZoomLevels: 22} + ) + ], + center: new OpenLayers.LonLat(10.2, 48.9) + // Google.v3 uses web mercator as projection, so we have to + // transform our coordinates + .transform('EPSG:4326', 'EPSG:3857'), + zoom: 5 + }); map.addControl(new OpenLayers.Control.LayerSwitcher()); - var gphy = new OpenLayers.Layer.Google( - "Google Physical", - {type: google.maps.MapTypeId.TERRAIN} - ); - var gmap = new OpenLayers.Layer.Google( - "Google Streets", // the default - {numZoomLevels: 20} - ); - var ghyb = new OpenLayers.Layer.Google( - "Google Hybrid", - {type: google.maps.MapTypeId.HYBRID, numZoomLevels: 20} - ); - var gsat = new OpenLayers.Layer.Google( - "Google Satellite", - {type: google.maps.MapTypeId.SATELLITE, numZoomLevels: 22} - ); - - map.addLayers([gphy, gmap, ghyb, gsat]); - - // Google.v3 uses EPSG:900913 as projection, so we have to - // transform our coordinates - map.setCenter(new OpenLayers.LonLat(10.2, 48.9).transform( - new OpenLayers.Projection("EPSG:4326"), - map.getProjectionObject() - ), 5); - // add behavior to html var animate = document.getElementById("animate"); animate.onclick = function() { diff --git a/examples/spherical-mercator.html b/examples/spherical-mercator.html index b2835701d8..443ba3bb86 100644 --- a/examples/spherical-mercator.html +++ b/examples/spherical-mercator.html @@ -17,6 +17,10 @@ right: inherit; width: 400px; } + /* conditionally position control differently for Google Maps */ + .olForeignContainer div.olControlMousePosition { + bottom: 28px; + } #map { height: 512px; } @@ -38,7 +42,12 @@

-
+
+

Note that maps with Google layers are a special case, because we + cannot control the position of the attribution. To conditionally + position controls differently for Google layers, prepend the + css selector with .olForeignContainer.

+
- * (end) - * - * but that development code should use the latest 'nightly' version, so that any - * problems can be dealt with as soon as they arise, and before they affect the production, 'frozen', code. - * - * Note, however, that frozen versions are retired as part of Google's release - * cycle, and once this happens, you will get the next version, in the example above, 3.8 once 3.7 is retired. - * - * This version supports 3.7. - * - * * 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. @@ -98,18 +69,13 @@ OpenLayers.Layer.Google.v3 = { ++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 + // create GMap var center = this.map.getCenter(); - mapObject = new google.maps.Map(div, { + var container = document.createElement('div'); + container.className = "olForeignContainer"; + container.style.width = '100%'; + container.style.height = '100%'; + mapObject = new google.maps.Map(container, { center: center ? new google.maps.LatLng(center.lat, center.lon) : new google.maps.LatLng(0, 0), @@ -130,87 +96,17 @@ OpenLayers.Layer.Google.v3 = { 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 - // depends on value of zIndex, which is not robust - for (var i=div.children.length-1; i>=0; --i) { - if (div.children[i].style.zIndex == 1000001) { - var termsOfUse = div.children[i]; - container.appendChild(termsOfUse); - termsOfUse.style.zIndex = "1100"; - termsOfUse.style.bottom = ""; - termsOfUse.className = "olLayerGoogleCopyright olLayerGoogleV3"; - termsOfUse.style.display = ""; - cache.termsOfUse = termsOfUse; - } - if (div.children[i].style.zIndex == 1000000) { - var poweredBy = div.children[i]; - container.appendChild(poweredBy); - poweredBy.style.zIndex = "1100"; - poweredBy.style.bottom = ""; - poweredBy.className = "olLayerGooglePoweredBy olLayerGoogleV3 gmnoprint"; - poweredBy.style.display = ""; - cache.poweredBy = poweredBy; - } - if (div.children[i].style.zIndex == 10000002) { - container.appendChild(div.children[i]); - } - } - - this.setGMapVisibility(this.visibility); - - }, - /** * APIMethod: onMapResize */ onMapResize: function() { if (this.visibility) { google.maps.event.trigger(this.mapObject, "resize"); - } else { - var cache = OpenLayers.Layer.Google.cache[this.map.id]; - if (!cache.resized) { - var layer = this; - google.maps.event.addListenerOnce(this.mapObject, "tilesloaded", function() { - google.maps.event.trigger(layer.mapObject, "resize"); - layer.moveTo(layer.map.getCenter(), layer.map.getZoom()); - delete cache.resized; - }); - } - cache.resized = true; } }, @@ -238,27 +134,34 @@ OpenLayers.Layer.Google.v3 = { } 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 = ""; + if (!cache.gmapHasViewport) { + this.map.div.removeChild(this.map.viewPortDiv); + this.mapObject.controls[google.maps.ControlPosition.TOP_LEFT].push(this.map.viewPortDiv); + cache.gmapHasViewport = true; + this.map.div.appendChild(container); + google.maps.event.trigger(this.mapObject, 'resize'); } + this.mapObject.setMapTypeId(type); 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"; + if (cache.gmapHasViewport) { + this.map.div.removeChild(container); + this.map.div.appendChild( + this.mapObject.controls[google.maps.ControlPosition.TOP_LEFT].pop() + ); + delete cache.gmapHasViewport; + + // restore all styles of the viewPortDiv, in case GMaps + // changes any. At the time of writing this, it definitely + // changes the position. + OpenLayers.Util.modifyDOMElement( + this.map.viewPortDiv, null, null, null, 'relative', + null, 'hidden' + ); + this.map.viewPortDiv.style.width = "100%"; + this.map.viewPortDiv.style.height = "100%"; } + delete cache.displayed; } } }, @@ -448,20 +351,6 @@ OpenLayers.Layer.Google.v3 = { */ 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); } }; diff --git a/lib/OpenLayers/Map.js b/lib/OpenLayers/Map.js index 5f4cf565a7..50eb3bc8c9 100644 --- a/lib/OpenLayers/Map.js +++ b/lib/OpenLayers/Map.js @@ -772,8 +772,8 @@ OpenLayers.Map = OpenLayers.Class({ } this.layers = null; } - if (this.viewPortDiv) { - this.div.removeChild(this.viewPortDiv); + if (this.viewPortDiv && this.viewPortDiv.parentNode) { + this.viewPortDiv.parentNode.removeChild(this.viewPortDiv); } this.viewPortDiv = null; diff --git a/tests/Layer/Google/v3.html b/tests/Layer/Google/v3.html index a90f8f46c1..10da99aea4 100644 --- a/tests/Layer/Google/v3.html +++ b/tests/Layer/Google/v3.html @@ -170,68 +170,6 @@ t.eq(satellite.div.style.display, "block", "Satellite layer is visible."); } - function test_Layer_Google_setGMapVisibility(t) { - t.plan(3); - - var map = new OpenLayers.Map('map'); - var gmap = new OpenLayers.Layer.Google("Google Streets"); - var dummy = new OpenLayers.Layer("Dummy", {isBaseLayer: true}); - map.addLayers([dummy, gmap]); - map.zoomToMaxExtent(); - - // In v3, the terms of use and powered by elements are not available - // until the layer loads. This can occur before the layer is visible, - // but we don't try to access these elements until after the layer is - // made visible for the first time. - var cache = OpenLayers.Layer.Google.cache[map.id]; - t.ok(!cache.termsOfUse, "termsOfUse is not yet cached"); - t.ok(!cache.poweredBy, "poweredBy is not yet cached"); - - var called = 0; - var original = gmap.repositionMapElements; - gmap.repositionMapElements = function() { - ++called; - original.apply(gmap, arguments); - } - - map.setBaseLayer(gmap); - t.delay_call(4, function() { - t.ok(called > 0, "repositionMapElements called"); - map.destroy(); - }); - } - - function test_Layer_Google_setGMapVisibility_allOverlays(t) { - t.plan(3); - - var map = new OpenLayers.Map('map', {allOverlays: true}); - var gmap = new OpenLayers.Layer.Google("Google Streets", {visibility: false}); - var dummy = new OpenLayers.Layer("Dummy"); - map.addLayers([gmap, dummy]); - map.zoomToMaxExtent(); - - // In v3, the terms of use and powered by elements are not available - // until the layer loads. This can occur before the layer is visible, - // but we don't try to access these elements until after the layer is - // made visible for the first time. - var cache = OpenLayers.Layer.Google.cache[map.id]; - t.ok(!cache.termsOfUse, "termsOfUse is not yet cached"); - t.ok(!cache.poweredBy, "poweredBy is not yet cached"); - - var called = 0; - var original = gmap.repositionMapElements; - gmap.repositionMapElements = function() { - ++called; - original.apply(gmap, arguments); - } - - gmap.setVisibility(true); - t.delay_call(2, function() { - t.ok(called > 0, "repositionMapElements called"); - map.destroy(); - }); - } - function test_allOverlays_invisible(t) { t.plan(1); @@ -319,10 +257,9 @@ t.plan(2); var origPrecision = OpenLayers.Util.DEFAULT_PRECISION; - // GMaps v3 seems to use a default precision of 13, which is lower - // than what we use in OpenLayers. + // Our default precision is very high - millimeters should be enough. // See http://trac.osgeo.org/openlayers/ticket/3059 - OpenLayers.Util.DEFAULT_PRECISION = 13; + OpenLayers.Util.DEFAULT_PRECISION = 12; var map = new OpenLayers.Map("map"); @@ -370,6 +307,28 @@ } + function test_moveViewportDiv(t) { + t.plan(2); + + var map = new OpenLayers.Map('map', { + projection: 'EPSG:3857', + center: [0, 0], + zoom: 1 + }); + var gmap = new OpenLayers.Layer.Google(); + map.addLayer(gmap); + + t.delay_call(1, function() { + t.ok(map.viewPortDiv.parentNode !== map.div, 'viewport moved inside GMaps'); + + var osm = new OpenLayers.Layer.OSM(); + map.addLayer(osm); + map.setBaseLayer(osm); + + t.ok(map.viewPortDiv.parentNode === map.div, 'viewport moved back'); + }); + } + diff --git a/theme/default/google.css b/theme/default/google.css index 3ee757c478..1b748ef3e5 100644 --- a/theme/default/google.css +++ b/theme/default/google.css @@ -3,15 +3,7 @@ bottom: 2px; left: auto; } -.olLayerGoogleV3.olLayerGoogleCopyright { - bottom: 0px; - right: 0px !important; -} .olLayerGooglePoweredBy { left: 2px; bottom: 2px; } -.olLayerGoogleV3.olLayerGooglePoweredBy { - bottom: 0px !important; -} -