No longer touching internal GMaps DOM elements.

Simple and effective: As soon as a map has a Google layer, the whole map viewport is added as control to the GMap. As soon as no Google layer is visible on the map any more, the map viewport is appended to the map container again. With this change, OpenLayers strictly limits its GMaps integration to the GMaps API.

Also note that there are no css overrides for the attribution any more. Instead, controls can now be conditionally positioned differently for Google layer by using the .olForeignContainer selector.
This commit is contained in:
ahocevar
2012-07-20 17:43:05 +02:00
parent 6075b599f3
commit 00d9664b95
7 changed files with 92 additions and 260 deletions

View File

@@ -15,35 +15,6 @@
*
* To use this layer, you must include the GMaps v3 API in your html.
*
* Because OpenLayers needs to control mouse events, it isolates the GMaps mapObject
* (the DOM elements provided by Google) using the EventPane.
* However, because the Terms of Use require some of those elements,
* such as the links to Google's terms, to be clickable, these elements have
* to be moved up to OpenLayers' container div. There is however no easy way
* to identify these, and the logic (see the repositionMapElements function
* in the source) may need to be changed if Google changes them.
* These elements are not part of the published API and can be changed at any time,
* so a given OpenLayers release can only guarantee support for the 'frozen'
* Google release at the time of the OpenLayers release. See
* https://developers.google.com/maps/documentation/javascript/basics#Versioning
* for Google's current release cycle.
*
* For this reason, it's recommended that production code specifically loads
* the current frozen version, for example:
*
* (code)
* <script src="http://maps.google.com/maps/api/js?v=3.7&amp;sensor=false"></script>
* (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);
}
};