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:
@@ -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"
|
||||
});
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
|
||||
143
tests/manual/vector-layer-zindex.html
Normal file
143
tests/manual/vector-layer-zindex.html
Normal 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>
|
||||
Reference in New Issue
Block a user