Made the Feature handler more robust to things that are related to changing layer order on the map, by registering an event handler that will bring the handler's layer back to the top of the layer stack in the DOM. Contains a manual test. r=elemoine (closes #1628)

git-svn-id: http://svn.openlayers.org/trunk/openlayers@7879 dc9f47b5-9b13-0410-9fdd-eb0c1a62fdaf
This commit is contained in:
ahocevar
2008-08-27 14:02:21 +00:00
parent 8e0876488b
commit 2a521ffcb2
5 changed files with 218 additions and 20 deletions

View File

@@ -100,12 +100,6 @@ OpenLayers.Handler.Feature = OpenLayers.Class(OpenLayers.Handler, {
*/
stopUp: false,
/**
* Property: layerIndex
* {Int}
*/
layerIndex: null,
/**
* Constructor: OpenLayers.Handler.Feature
*
@@ -300,16 +294,20 @@ OpenLayers.Handler.Feature = OpenLayers.Class(OpenLayers.Handler, {
activate: function() {
var activated = false;
if(OpenLayers.Handler.prototype.activate.apply(this, arguments)) {
this.layerIndex = this.layer.div.style.zIndex;
this.layer.div.style.zIndex = this.map.Z_INDEX_BASE['Popup'] - 1;
this.moveLayerToTop();
this.map.events.on({
"removelayer": this.handleMapEvents,
"changelayer": this.handleMapEvents,
scope: this
});
activated = true;
}
return activated;
},
/**
* Method: activate
* Turn of the handler. Returns false if the handler was already active.
* Method: deactivate
* Turn off the handler. Returns false if the handler was already active.
*
* Returns:
* {Boolean}
@@ -317,17 +315,59 @@ OpenLayers.Handler.Feature = OpenLayers.Class(OpenLayers.Handler, {
deactivate: function() {
var deactivated = false;
if(OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
if (this.layer && this.layer.div) {
this.layer.div.style.zIndex = this.layerIndex;
}
this.moveLayerBack();
this.feature = null;
this.lastFeature = null;
this.down = null;
this.up = null;
this.map.events.un({
"removelayer": this.handleMapEvents,
"changelayer": this.handleMapEvents,
scope: this
});
deactivated = true;
}
return deactivated;
},
/**
* Method handleMapEvents
*
* Parameters:
* evt - {Object}
*/
handleMapEvents: function(evt) {
if (!evt.property || evt.property == "order") {
this.moveLayerToTop();
}
},
/**
* Method: moveLayerToTop
* Moves the layer for this handler to the top, so mouse events can reach
* it.
*/
moveLayerToTop: function() {
var index = Math.max(this.map.Z_INDEX_BASE['Feature'] - 1,
this.layer.getZIndex()) + 1;
this.layer.setZIndex(index);
},
/**
* Method: moveLayerBack
* Moves the layer back to the position determined by the map's layers
* array.
*/
moveLayerBack: function() {
var index = this.layer.getZIndex() - 1;
if (index >= this.map.Z_INDEX_BASE['Feature']) {
this.layer.setZIndex(index);
} else {
this.map.setLayerZIndex(this.layer,
this.map.getLayerIndex(this.layer));
}
},
CLASS_NAME: "OpenLayers.Handler.Feature"
});

View File

@@ -1098,6 +1098,16 @@ OpenLayers.Layer = OpenLayers.Class({
}
},
/**
* Method: getZIndex
*
* Returns:
* {Integer} the z-index of this layer
*/
getZIndex: function () {
return this.div.style.zIndex;
},
/**
* Method: setZIndex
*

View File

@@ -23,7 +23,13 @@ OpenLayers.Map = OpenLayers.Class({
* Constant: Z_INDEX_BASE
* {Object} Base z-indexes for different classes of thing
*/
Z_INDEX_BASE: { BaseLayer: 100, Overlay: 325, Popup: 750, Control: 1000 },
Z_INDEX_BASE: {
BaseLayer: 100,
Overlay: 325,
Feature: 725,
Popup: 750,
Control: 1000
},
/**
* Constant: EVENT_TYPES

View File

@@ -30,7 +30,7 @@
}
function test_Handler_Feature_activate(t) {
t.plan(4);
t.plan(3);
var map = new OpenLayers.Map('map');
var control = new OpenLayers.Control();
map.addControl(control);
@@ -47,10 +47,8 @@
activated = handler.activate();
t.ok(activated,
"activate returns true if the handler was not already active");
t.eq(handler.layerIndex, zIndex,
"layerIndex property properly set");
t.eq(parseInt(layer.div.style.zIndex),
map.Z_INDEX_BASE['Popup'] - 1,
map.Z_INDEX_BASE['Feature'],
"layer z-index properly adjusted");
}
@@ -227,6 +225,8 @@
map.addControl(control);
var layer = new OpenLayers.Layer();
map.addLayer(layer);
var layerIndex = parseInt(layer.div.style.zIndex);
var handler = new OpenLayers.Handler.Feature(control, layer);
handler.active = false;
var deactivated = handler.deactivate();
@@ -234,13 +234,12 @@
"deactivate returns false if the handler was not already active");
handler.active = true;
handler.layerIndex = Math.floor(Math.random() * 10);
deactivated = handler.deactivate();
t.ok(deactivated,
"deactivate returns true if the handler was active already");
t.eq(parseInt(layer.div.style.zIndex),
handler.layerIndex,
layerIndex,
"deactivate sets the layer z-index back");
}

View File

@@ -0,0 +1,143 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Vector Layer ZIndex Test</title>
<style type="text/css">
body {
font-size: 0.8em;
}
p {
padding-top: 1em;
}
#map {
margin: 1em;
width: 512px;
height: 512px;
}
</style>
<script src="../../lib/OpenLayers.js"></script>
<script type="text/javascript">
var map, layerA, layerB, layerV, selectControl1, selectControl2;
function init() {
map = new OpenLayers.Map('map');
var wmsLayer = new OpenLayers.Layer.WMS(
"OpenLayers WMS",
"http://labs.metacarta.com/wms/vmap0",
{layers: 'basic'}
);
layerV = new OpenLayers.Layer.Vector('v');
var feature = new OpenLayers.Feature.Vector(
new OpenLayers.Geometry.Polygon([
new OpenLayers.Geometry.LinearRing([
new OpenLayers.Geometry.Point(-110, 60),
new OpenLayers.Geometry.Point(-110, 30),
new OpenLayers.Geometry.Point(-80, 30),
new OpenLayers.Geometry.Point(-110, 60)
])
])
);
layerV.addFeatures([feature]);
selectControl1 = new OpenLayers.Control.SelectFeature(layerV);
selectControl2 = new OpenLayers.Control.SelectFeature(layerV, {
hover: true,
selectStyle: OpenLayers.Util.applyDefaults({fillColor: "red"}, OpenLayers.Feature.Vector.style["select"]),
onSelect: function(feature) {
selectControl2.unselect(feature);
layerV.drawFeature(feature, selectControl2.selectStyle);
}
});
selectControl2.events.register("beforefeatureselected", null, function(feature) {
layerV.drawFeature(feature, selectControl2.selectStyle);
return false;
})
layerA = new OpenLayers.Layer('a', {'isBaseLayer': false});
layerB = new OpenLayers.Layer.WMS(
'b', 'http://www2.dmsolutions.ca/cgi-bin/mswms_gmap', {
'layers': [
'bathymetry', 'land_fn', 'park', 'drain_fn', 'drainage',
'prov_bound', 'fedlimit', 'rail', 'road', 'popplace'
],
'transparent': 'true',
'format': 'image/png'
}, {
'reproject': false
});
map.addLayers([wmsLayer, layerV, layerA, layerB]);
map.addControl(selectControl2);
map.addControl(selectControl1);
map.addControl(new OpenLayers.Control.MousePosition());
selectControl2.activate();
selectControl1.activate();
map.setCenter(new OpenLayers.LonLat(-90, 20), 2);
}
function removeLayerA() {
if (OpenLayers.Util.indexOf(map.layers, layerA) > -1) {
map.removeLayer(layerA);
}
}
function toggleSelectControl1() {
if (selectControl1.active) {
selectControl1.deactivate();
alert("SelectFeature control for clicks deactivated.");
} else {
selectControl1.activate();
alert("SelectFeature control for clicks activated.");
}
}
function toggleSelectControl2() {
if (selectControl2.active) {
selectControl2.deactivate();
alert("SelectFeature control for hover deactivated.");
} else {
selectControl2.activate();
alert("SelectFeature control for hover activated.");
}
}
</script>
</head>
<body onload="init()">
<h1 id="title">Vector Layer ZIndex Test</h1>
<div id="map"></div>
<p>
The map includes one base layer (vmap0) and three overlays, namely a vector
layer, a fake layer with no images, and a dmsolutions layer. The overlays are
added to the map in this order: the vector layer, the fake layer, and the
dmsolutions layer. The map also includes a select feature control, which
when activated bumped the vector layer z-index to some high value. This
makes feature selection work, even though other overlays were added after
the vector layer.
</p>
<p>
If the fake layer is removed from the map (first link below), the vector layer's
z-index must not be reset, so the vector layer must not go under the
dmsolutions layer and feature selection must continue to function as
expected.
</p>
<p>
If one of the SelectFeature controls is deactivated or activated (second
and third link below), the vector layer should change it's position in the
layer stack: on top if at least one of the controls is activated, covered
by other layers if both are deactivated.
</p>
<p>
<a href="javascript:removeLayerA()">Remove the fake layer</a>
<br/><a href="javascript:toggleSelectControl1()">Toggle the click SelectFeature control's active status</a>
<br/><a href="javascript:toggleSelectControl2()">Toggle the hover SelectFeature control's active status</a>
</p>
</body>
</html>