SelectFeature control can now select across multiple vector
layers when passed an array of layers instead of a single layer with the constructor. This changeset also introduces a new layer type, Layer.Vector.RootContainer, which will be set as the topmost layer by the SelectFeature control and collect the svg/vml/canvas roots of multiple vector layers. r=crschmidt (closes #1666) git-svn-id: http://svn.openlayers.org/trunk/openlayers@9116 dc9f47b5-9b13-0410-9fdd-eb0c1a62fdaf
This commit is contained in:
116
examples/select-feature-multilayer.html
Normal file
116
examples/select-feature-multilayer.html
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||||
|
<head>
|
||||||
|
<title>SelectFeature Control on multiple vector layers</title>
|
||||||
|
<link rel="stylesheet" href="../theme/default/style.css" type="text/css" />
|
||||||
|
<link rel="stylesheet" href="style.css" type="text/css" />
|
||||||
|
<style type="text/css">
|
||||||
|
#controlToggle li {
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script src="../lib/OpenLayers.js"></script>
|
||||||
|
<script type="text/javascript">
|
||||||
|
var map, drawControls;
|
||||||
|
OpenLayers.Feature.Vector.style['default']['strokeWidth'] = '2';
|
||||||
|
function init(){
|
||||||
|
map = new OpenLayers.Map('map');
|
||||||
|
var wmsLayer = new OpenLayers.Layer.WMS(
|
||||||
|
"OpenLayers WMS",
|
||||||
|
"http://labs.metacarta.com/wms/vmap0",
|
||||||
|
{layers: 'basic'}
|
||||||
|
);
|
||||||
|
|
||||||
|
var vectors1 = new OpenLayers.Layer.Vector("Vector Layer 1", {
|
||||||
|
styleMap: new OpenLayers.StyleMap({
|
||||||
|
"default": new OpenLayers.Style(OpenLayers.Util.applyDefaults({
|
||||||
|
externalGraphic: "../img/marker-green.png",
|
||||||
|
graphicOpacity: 1,
|
||||||
|
rotation: -45,
|
||||||
|
pointRadius: 10
|
||||||
|
}, OpenLayers.Feature.Vector.style["default"])),
|
||||||
|
"select": new OpenLayers.Style({
|
||||||
|
externalGraphic: "../img/marker-blue.png"
|
||||||
|
})
|
||||||
|
})
|
||||||
|
});
|
||||||
|
var vectors2 = new OpenLayers.Layer.Vector("Vector Layer 2", {
|
||||||
|
styleMap: new OpenLayers.StyleMap({
|
||||||
|
"default": new OpenLayers.Style(OpenLayers.Util.applyDefaults({
|
||||||
|
fillColor: "red",
|
||||||
|
strokeColor: "gray",
|
||||||
|
graphicName: "square",
|
||||||
|
rotation: 45,
|
||||||
|
pointRadius: 15
|
||||||
|
}, OpenLayers.Feature.Vector.style["default"])),
|
||||||
|
"select": new OpenLayers.Style(OpenLayers.Util.applyDefaults({
|
||||||
|
graphicName: "square",
|
||||||
|
rotation: 45,
|
||||||
|
pointRadius: 15
|
||||||
|
}, OpenLayers.Feature.Vector.style["select"]))
|
||||||
|
})
|
||||||
|
});
|
||||||
|
map.addLayers([wmsLayer, vectors1, vectors2]);
|
||||||
|
map.addControl(new OpenLayers.Control.LayerSwitcher());
|
||||||
|
|
||||||
|
var selectControl = new OpenLayers.Control.SelectFeature(
|
||||||
|
[vectors1, vectors2],
|
||||||
|
{
|
||||||
|
clickout: true, toggle: false,
|
||||||
|
multiple: false, hover: false,
|
||||||
|
toggleKey: "ctrlKey", // ctrl key removes from selection
|
||||||
|
multipleKey: "shiftKey" // shift key adds to selection
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
map.addControl(selectControl);
|
||||||
|
selectControl.activate();
|
||||||
|
map.setCenter(new OpenLayers.LonLat(0, 0), 3);
|
||||||
|
vectors1.addFeatures(createFeatures());
|
||||||
|
vectors2.addFeatures(createFeatures());
|
||||||
|
|
||||||
|
vectors1.events.on({
|
||||||
|
"featureselected": function(e) {
|
||||||
|
showStatus("selected feature "+e.feature.id+" on Vector Layer 1");
|
||||||
|
},
|
||||||
|
"featureunselected": function(e) {
|
||||||
|
showStatus("unselected feature "+e.feature.id+" on Vector Layer 1");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
vectors2.events.on({
|
||||||
|
"featureselected": function(e) {
|
||||||
|
showStatus("selected feature "+e.feature.id+" on Vector Layer 2");
|
||||||
|
},
|
||||||
|
"featureunselected": function(e) {
|
||||||
|
showStatus("unselected feature "+e.feature.id+" on Vector Layer 2");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function createFeatures() {
|
||||||
|
var extent = map.getExtent();
|
||||||
|
var features = [];
|
||||||
|
for(var i=0; i<10; ++i) {
|
||||||
|
features.push(new OpenLayers.Feature.Vector(
|
||||||
|
new OpenLayers.Geometry.Point(extent.left + (extent.right - extent.left) * Math.random(),
|
||||||
|
extent.bottom + (extent.top - extent.bottom) * Math.random()
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
return features;
|
||||||
|
}
|
||||||
|
|
||||||
|
function showStatus(text) {
|
||||||
|
document.getElementById("status").innerHTML = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body onload="init()">
|
||||||
|
<h1 id="title">OpenLayers Select Feature on Multiple Layers Example</h1>
|
||||||
|
<p id="shortdesc">
|
||||||
|
Select a feature on click with the Control.SelectFeature on multiple
|
||||||
|
vector layers.
|
||||||
|
</p>
|
||||||
|
<div id="map" class="smallmap"></div>
|
||||||
|
<div id="status"></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -181,6 +181,7 @@
|
|||||||
"OpenLayers/Renderer/Canvas.js",
|
"OpenLayers/Renderer/Canvas.js",
|
||||||
"OpenLayers/Renderer/VML.js",
|
"OpenLayers/Renderer/VML.js",
|
||||||
"OpenLayers/Layer/Vector.js",
|
"OpenLayers/Layer/Vector.js",
|
||||||
|
"OpenLayers/Layer/Vector/RootContainer.js",
|
||||||
"OpenLayers/Strategy.js",
|
"OpenLayers/Strategy.js",
|
||||||
"OpenLayers/Strategy/Fixed.js",
|
"OpenLayers/Strategy/Fixed.js",
|
||||||
"OpenLayers/Strategy/Cluster.js",
|
"OpenLayers/Strategy/Cluster.js",
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
* @requires OpenLayers/Control.js
|
* @requires OpenLayers/Control.js
|
||||||
* @requires OpenLayers/Feature/Vector.js
|
* @requires OpenLayers/Feature/Vector.js
|
||||||
* @requires OpenLayers/Handler/Feature.js
|
* @requires OpenLayers/Handler/Feature.js
|
||||||
|
* @requires OpenLayers/Layer/Vector/RootContainer.js
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -103,10 +104,17 @@ OpenLayers.Control.SelectFeature = OpenLayers.Class(OpenLayers.Control, {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Property: layer
|
* Property: layer
|
||||||
* {<OpenLayers.Layer.Vector>}
|
* {<OpenLayers.Layer.Vector>} The vector layer with a common renderer
|
||||||
|
* root for all layers this control is configured with.
|
||||||
*/
|
*/
|
||||||
layer: null,
|
layer: null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Property: layers
|
||||||
|
* {Array(<OpenLayers.Layer.Vector>} The layers this control will work on.
|
||||||
|
*/
|
||||||
|
layers: null,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* APIProperty: callbacks
|
* APIProperty: callbacks
|
||||||
* {Object} The functions that are sent to the handlers.feature for callback
|
* {Object} The functions that are sent to the handlers.feature for callback
|
||||||
@@ -137,12 +145,20 @@ OpenLayers.Control.SelectFeature = OpenLayers.Class(OpenLayers.Control, {
|
|||||||
* Constructor: <OpenLayers.Control.SelectFeature>
|
* Constructor: <OpenLayers.Control.SelectFeature>
|
||||||
*
|
*
|
||||||
* Parameters:
|
* Parameters:
|
||||||
* layer - {<OpenLayers.Layer.Vector>}
|
* layers - {<OpenLayers.Layer.Vector>}, or an array of vector layers
|
||||||
* options - {Object}
|
* options - {Object}
|
||||||
*/
|
*/
|
||||||
initialize: function(layer, options) {
|
initialize: function(layers, options) {
|
||||||
OpenLayers.Control.prototype.initialize.apply(this, [options]);
|
OpenLayers.Control.prototype.initialize.apply(this, [options]);
|
||||||
this.layer = layer;
|
if(!(layers instanceof Array)) {
|
||||||
|
layers = [layers];
|
||||||
|
}
|
||||||
|
this.layers = layers;
|
||||||
|
this.layer = new OpenLayers.Layer.Vector.RootContainer(
|
||||||
|
this.id + "_container", {
|
||||||
|
layers: layers
|
||||||
|
}
|
||||||
|
);
|
||||||
var callbacks = {
|
var callbacks = {
|
||||||
click: this.clickFeature,
|
click: this.clickFeature,
|
||||||
clickout: this.clickoutFeature
|
clickout: this.clickoutFeature
|
||||||
@@ -155,7 +171,8 @@ OpenLayers.Control.SelectFeature = OpenLayers.Class(OpenLayers.Control, {
|
|||||||
this.callbacks = OpenLayers.Util.extend(callbacks, this.callbacks);
|
this.callbacks = OpenLayers.Util.extend(callbacks, this.callbacks);
|
||||||
this.handlers = {
|
this.handlers = {
|
||||||
feature: new OpenLayers.Handler.Feature(
|
feature: new OpenLayers.Handler.Feature(
|
||||||
this, layer, this.callbacks, {geometryTypes: this.geometryTypes}
|
this, this.layer, this.callbacks,
|
||||||
|
{geometryTypes: this.geometryTypes}
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -166,6 +183,14 @@ OpenLayers.Control.SelectFeature = OpenLayers.Class(OpenLayers.Control, {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method: destroy
|
||||||
|
*/
|
||||||
|
destroy: function() {
|
||||||
|
OpenLayers.Control.prototype.destroy.apply(this, arguments);
|
||||||
|
this.layer.destroy();
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method: activate
|
* Method: activate
|
||||||
@@ -176,6 +201,7 @@ OpenLayers.Control.SelectFeature = OpenLayers.Class(OpenLayers.Control, {
|
|||||||
*/
|
*/
|
||||||
activate: function () {
|
activate: function () {
|
||||||
if (!this.active) {
|
if (!this.active) {
|
||||||
|
this.map.addLayer(this.layer);
|
||||||
this.handlers.feature.activate();
|
this.handlers.feature.activate();
|
||||||
if(this.box && this.handlers.box) {
|
if(this.box && this.handlers.box) {
|
||||||
this.handlers.box.activate();
|
this.handlers.box.activate();
|
||||||
@@ -199,6 +225,9 @@ OpenLayers.Control.SelectFeature = OpenLayers.Class(OpenLayers.Control, {
|
|||||||
if(this.handlers.box) {
|
if(this.handlers.box) {
|
||||||
this.handlers.box.deactivate();
|
this.handlers.box.deactivate();
|
||||||
}
|
}
|
||||||
|
this.map.events.unregister("changelayer", this.layer,
|
||||||
|
this.layer.handleChangeLayer);
|
||||||
|
this.map.removeLayer(this.layer);
|
||||||
}
|
}
|
||||||
return OpenLayers.Control.prototype.deactivate.apply(
|
return OpenLayers.Control.prototype.deactivate.apply(
|
||||||
this, arguments
|
this, arguments
|
||||||
@@ -215,11 +244,14 @@ OpenLayers.Control.SelectFeature = OpenLayers.Class(OpenLayers.Control, {
|
|||||||
*/
|
*/
|
||||||
unselectAll: function(options) {
|
unselectAll: function(options) {
|
||||||
// we'll want an option to supress notification here
|
// we'll want an option to supress notification here
|
||||||
var feature;
|
var layer, feature;
|
||||||
for(var i=this.layer.selectedFeatures.length-1; i>=0; --i) {
|
for(var l=0; l<this.layers.length; ++l) {
|
||||||
feature = this.layer.selectedFeatures[i];
|
layer = this.layers[l];
|
||||||
if(!options || options.except != feature) {
|
for(var i=layer.selectedFeatures.length-1; i>=0; --i) {
|
||||||
this.unselect(feature);
|
feature = layer.selectedFeatures[i];
|
||||||
|
if(!options || options.except != feature) {
|
||||||
|
this.unselect(feature);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -234,8 +266,8 @@ OpenLayers.Control.SelectFeature = OpenLayers.Class(OpenLayers.Control, {
|
|||||||
*/
|
*/
|
||||||
clickFeature: function(feature) {
|
clickFeature: function(feature) {
|
||||||
if(!this.hover) {
|
if(!this.hover) {
|
||||||
var selected = (OpenLayers.Util.indexOf(this.layer.selectedFeatures,
|
var selected = (OpenLayers.Util.indexOf(
|
||||||
feature) > -1);
|
feature.layer.selectedFeatures, feature) > -1);
|
||||||
if(selected) {
|
if(selected) {
|
||||||
if(this.toggleSelect()) {
|
if(this.toggleSelect()) {
|
||||||
this.unselect(feature);
|
this.unselect(feature);
|
||||||
@@ -301,7 +333,7 @@ OpenLayers.Control.SelectFeature = OpenLayers.Class(OpenLayers.Control, {
|
|||||||
*/
|
*/
|
||||||
overFeature: function(feature) {
|
overFeature: function(feature) {
|
||||||
if(this.hover &&
|
if(this.hover &&
|
||||||
(OpenLayers.Util.indexOf(this.layer.selectedFeatures, feature) == -1)) {
|
(OpenLayers.Util.indexOf(feature.layer.selectedFeatures, feature) == -1)) {
|
||||||
this.select(feature);
|
this.select(feature);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -330,17 +362,19 @@ OpenLayers.Control.SelectFeature = OpenLayers.Class(OpenLayers.Control, {
|
|||||||
*/
|
*/
|
||||||
select: function(feature) {
|
select: function(feature) {
|
||||||
var cont = this.onBeforeSelect.call(this.scope, feature);
|
var cont = this.onBeforeSelect.call(this.scope, feature);
|
||||||
|
var layer = feature.layer;
|
||||||
if(cont !== false) {
|
if(cont !== false) {
|
||||||
cont = this.layer.events.triggerEvent("beforefeatureselected", {
|
cont = layer.events.triggerEvent("beforefeatureselected", {
|
||||||
feature: feature
|
feature: feature
|
||||||
});
|
});
|
||||||
if(cont !== false) {
|
if(cont !== false) {
|
||||||
this.layer.selectedFeatures.push(feature);
|
layer.selectedFeatures.push(feature);
|
||||||
|
this.layerData = {};
|
||||||
|
|
||||||
var selectStyle = this.selectStyle || this.renderIntent;
|
var selectStyle = this.selectStyle || this.renderIntent;
|
||||||
|
|
||||||
this.layer.drawFeature(feature, selectStyle);
|
layer.drawFeature(feature, selectStyle);
|
||||||
this.layer.events.triggerEvent("featureselected", {feature: feature});
|
layer.events.triggerEvent("featureselected", {feature: feature});
|
||||||
this.onSelect.call(this.scope, feature);
|
this.onSelect.call(this.scope, feature);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -355,10 +389,11 @@ OpenLayers.Control.SelectFeature = OpenLayers.Class(OpenLayers.Control, {
|
|||||||
* feature - {<OpenLayers.Feature.Vector>}
|
* feature - {<OpenLayers.Feature.Vector>}
|
||||||
*/
|
*/
|
||||||
unselect: function(feature) {
|
unselect: function(feature) {
|
||||||
|
var layer = feature.layer;
|
||||||
// Store feature style for restoration later
|
// Store feature style for restoration later
|
||||||
this.layer.drawFeature(feature, "default");
|
layer.drawFeature(feature, "default");
|
||||||
OpenLayers.Util.removeItem(this.layer.selectedFeatures, feature);
|
OpenLayers.Util.removeItem(layer.selectedFeatures, feature);
|
||||||
this.layer.events.triggerEvent("featureunselected", {feature: feature});
|
layer.events.triggerEvent("featureunselected", {feature: feature});
|
||||||
this.onUnselect.call(this.scope, feature);
|
this.onUnselect.call(this.scope, feature);
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -390,13 +425,17 @@ OpenLayers.Control.SelectFeature = OpenLayers.Class(OpenLayers.Control, {
|
|||||||
// because we're using a box, we consider we want multiple selection
|
// because we're using a box, we consider we want multiple selection
|
||||||
var prevMultiple = this.multiple;
|
var prevMultiple = this.multiple;
|
||||||
this.multiple = true;
|
this.multiple = true;
|
||||||
for(var i=0, len = this.layer.features.length; i<len; ++i) {
|
var layer;
|
||||||
var feature = this.layer.features[i];
|
for(var l=0; l<this.layers.length; ++l) {
|
||||||
if (this.geometryTypes == null || OpenLayers.Util.indexOf(
|
layer = this.layers[l];
|
||||||
this.geometryTypes, feature.geometry.CLASS_NAME) > -1) {
|
for(var i=0, len = layer.features.length; i<len; ++i) {
|
||||||
if (bounds.toGeometry().intersects(feature.geometry)) {
|
var feature = layer.features[i];
|
||||||
if (OpenLayers.Util.indexOf(this.layer.selectedFeatures, feature) == -1) {
|
if (this.geometryTypes == null || OpenLayers.Util.indexOf(
|
||||||
this.select(feature);
|
this.geometryTypes, feature.geometry.CLASS_NAME) > -1) {
|
||||||
|
if (bounds.toGeometry().intersects(feature.geometry)) {
|
||||||
|
if (OpenLayers.Util.indexOf(layer.selectedFeatures, feature) == -1) {
|
||||||
|
this.select(feature);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -419,6 +458,6 @@ OpenLayers.Control.SelectFeature = OpenLayers.Class(OpenLayers.Control, {
|
|||||||
}
|
}
|
||||||
OpenLayers.Control.prototype.setMap.apply(this, arguments);
|
OpenLayers.Control.prototype.setMap.apply(this, arguments);
|
||||||
},
|
},
|
||||||
|
|
||||||
CLASS_NAME: "OpenLayers.Control.SelectFeature"
|
CLASS_NAME: "OpenLayers.Control.SelectFeature"
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -445,6 +445,23 @@ OpenLayers.Layer.Vector = OpenLayers.Class(OpenLayers.Layer, {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* APIMethod: display
|
||||||
|
* Hide or show the Layer
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* display - {Boolean}
|
||||||
|
*/
|
||||||
|
display: function(display) {
|
||||||
|
OpenLayers.Layer.prototype.display.apply(this, arguments);
|
||||||
|
// we need to set the display style of the root in case it is attached
|
||||||
|
// to a foreign layer
|
||||||
|
var currentDisplay = this.div.style.display;
|
||||||
|
if(currentDisplay != this.renderer.root.style.display) {
|
||||||
|
this.renderer.root.style.display = currentDisplay;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* APIMethod: addFeatures
|
* APIMethod: addFeatures
|
||||||
|
|||||||
156
lib/OpenLayers/Layer/Vector/RootContainer.js
Normal file
156
lib/OpenLayers/Layer/Vector/RootContainer.js
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
|
||||||
|
* license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
|
||||||
|
* full text of the license. */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @requires OpenLayers/Layer/Vector.js
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class: OpenLayers.Layer.Vector.RootContainer
|
||||||
|
* A special layer type to combine multiple vector layers inside a single
|
||||||
|
* renderer root container. This class is not supposed to be instantiated
|
||||||
|
* from user space, it is a helper class for controls that require event
|
||||||
|
* processing for multiple vector layers.
|
||||||
|
*
|
||||||
|
* Inherits from:
|
||||||
|
* - <OpenLayers.Layer.Vector>
|
||||||
|
*/
|
||||||
|
OpenLayers.Layer.Vector.RootContainer = OpenLayers.Class(OpenLayers.Layer.Vector, {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Property: displayInLayerSwitcher
|
||||||
|
* Set to false for this layer type
|
||||||
|
*/
|
||||||
|
displayInLayerSwitcher: false,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* APIProperty: layers
|
||||||
|
* Layers that are attached to this container. Required config option.
|
||||||
|
*/
|
||||||
|
layers: null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor: OpenLayers.Layer.Vector.RootContainer
|
||||||
|
* Create a new root container for multiple vector layer. This constructor
|
||||||
|
* is not supposed to be used from user space, it is only to be used by
|
||||||
|
* controls that need feature selection across multiple vector layers.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* name - {String} A name for the layer
|
||||||
|
* options - {Object} Optional object with non-default properties to set on
|
||||||
|
* the layer.
|
||||||
|
*
|
||||||
|
* Required options properties:
|
||||||
|
* layers - {Array(<OpenLayers.Layer.Vector>)} The layers managed by this
|
||||||
|
* container
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* {<OpenLayers.Layer.Vector.RootContainer>} A new vector layer root
|
||||||
|
* container
|
||||||
|
*/
|
||||||
|
initialize: function(name, options) {
|
||||||
|
OpenLayers.Layer.Vector.prototype.initialize.apply(this, arguments);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method: display
|
||||||
|
*/
|
||||||
|
display: function() {},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method: getFeatureFromEvent
|
||||||
|
* walk through the layers to find the feature returned by the event
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* evt - {Object} event object with a feature property
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* {<OpenLayers.Feature.Vector>}
|
||||||
|
*/
|
||||||
|
getFeatureFromEvent: function(evt) {
|
||||||
|
var layers = this.layers;
|
||||||
|
var feature;
|
||||||
|
for(var i=0; i<layers.length; i++) {
|
||||||
|
feature = layers[i].getFeatureFromEvent(evt);
|
||||||
|
if(feature) {
|
||||||
|
return feature;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method: setMap
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* map - {<OpenLayers.Map>}
|
||||||
|
*/
|
||||||
|
setMap: function(map) {
|
||||||
|
OpenLayers.Layer.Vector.prototype.setMap.apply(this, arguments);
|
||||||
|
this.collectRoots();
|
||||||
|
map.events.register("changelayer", this, this.handleChangeLayer);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method: removeMap
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* map - {<OpenLayers.Map>}
|
||||||
|
*/
|
||||||
|
removeMap: function(map) {
|
||||||
|
map.events.unregister("changelayer", this, this.handleChangeLayer);
|
||||||
|
this.resetRoots();
|
||||||
|
OpenLayers.Layer.Vector.prototype.removeMap.apply(this, arguments);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method: collectRoots
|
||||||
|
* Collects the root nodes of all layers this control is configured with
|
||||||
|
* and moveswien the nodes to this control's layer
|
||||||
|
*/
|
||||||
|
collectRoots: function() {
|
||||||
|
var layer;
|
||||||
|
// walk through all map layers, because we want to keep the order
|
||||||
|
for(var i=0; i<this.map.layers.length; ++i) {
|
||||||
|
layer = this.map.layers[i];
|
||||||
|
if(OpenLayers.Util.indexOf(this.layers, layer) != -1) {
|
||||||
|
layer.renderer.moveRoot(this.renderer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method: resetRoots
|
||||||
|
* Resets the root nodes back into the layers they belong to.
|
||||||
|
*/
|
||||||
|
resetRoots: function() {
|
||||||
|
var layer;
|
||||||
|
for(var i=0; i<this.layers.length; ++i) {
|
||||||
|
layer = this.layers[i];
|
||||||
|
if(layer.renderer.getRenderLayer() == this) {
|
||||||
|
this.renderer.moveRoot(layer.renderer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method: handleChangeLayer
|
||||||
|
* Event handler for the map's changelayer event. We need to rebuild
|
||||||
|
* this container's layer dom if order of one of its layers changes.
|
||||||
|
* This handler is added with the setMap method, and removed with the
|
||||||
|
* removeMap method.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* evt - {Object}
|
||||||
|
*/
|
||||||
|
handleChangeLayer: function(evt) {
|
||||||
|
var layer = evt.layer;
|
||||||
|
if(evt.property == "order" &&
|
||||||
|
OpenLayers.Util.indexOf(this.layers, layer) != -1) {
|
||||||
|
this.resetRoots();
|
||||||
|
this.collectRoots();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
CLASS_NAME: "OpenLayers.Layer.Vector.RootContainer"
|
||||||
|
});
|
||||||
@@ -392,6 +392,20 @@ OpenLayers.Layer.WFS = OpenLayers.Class(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method: display
|
||||||
|
* Call the display method of the appropriate parent class.
|
||||||
|
*/
|
||||||
|
display: function() {
|
||||||
|
if(this.vectorMode) {
|
||||||
|
OpenLayers.Layer.Vector.prototype.display.apply(this,
|
||||||
|
arguments);
|
||||||
|
} else {
|
||||||
|
OpenLayers.Layer.Markers.prototype.display.apply(this,
|
||||||
|
arguments);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* APIMethod: mergeNewParams
|
* APIMethod: mergeNewParams
|
||||||
* Modify parameters for the layer and redraw.
|
* Modify parameters for the layer and redraw.
|
||||||
|
|||||||
@@ -27,6 +27,12 @@ OpenLayers.Renderer = OpenLayers.Class({
|
|||||||
*/
|
*/
|
||||||
container: null,
|
container: null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Property: root
|
||||||
|
* {DOMElement}
|
||||||
|
*/
|
||||||
|
root: null,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Property: extent
|
* Property: extent
|
||||||
* {<OpenLayers.Bounds>}
|
* {<OpenLayers.Bounds>}
|
||||||
@@ -237,6 +243,32 @@ OpenLayers.Renderer = OpenLayers.Class({
|
|||||||
* geometry - {<OpenLayers.Geometry>}
|
* geometry - {<OpenLayers.Geometry>}
|
||||||
*/
|
*/
|
||||||
eraseGeometry: function(geometry) {},
|
eraseGeometry: function(geometry) {},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method: moveRoot
|
||||||
|
* moves this renderer's root to a (different) renderer.
|
||||||
|
* To be implemented by subclasses that require a common renderer root for
|
||||||
|
* feature selection.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* renderer - {<OpenLayers.Renderer>} target renderer for the moved root
|
||||||
|
*/
|
||||||
|
moveRoot: function(renderer) {},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method: getRenderLayer
|
||||||
|
* Gets the layer that this renderer's output appears on. If moveRoot was
|
||||||
|
* used, this will be different from the layer containing the features
|
||||||
|
* rendered by this renderer.
|
||||||
|
* To be overridden by subclasses that implement moveRoot.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* {<OpenLayers.Layer.Vector>} the output layer, if any (i.e. this method
|
||||||
|
* will not return a layer if the layer is not added to a map).
|
||||||
|
*/
|
||||||
|
getRenderLayer: function() {
|
||||||
|
return this.map.getLayer(this.container.id);
|
||||||
|
},
|
||||||
|
|
||||||
CLASS_NAME: "OpenLayers.Renderer"
|
CLASS_NAME: "OpenLayers.Renderer"
|
||||||
});
|
});
|
||||||
@@ -15,12 +15,6 @@
|
|||||||
*/
|
*/
|
||||||
OpenLayers.Renderer.Canvas = OpenLayers.Class(OpenLayers.Renderer, {
|
OpenLayers.Renderer.Canvas = OpenLayers.Class(OpenLayers.Renderer, {
|
||||||
|
|
||||||
/**
|
|
||||||
* Property: root
|
|
||||||
* {DOMElement} root element of canvas.
|
|
||||||
*/
|
|
||||||
root: null,
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Property: canvas
|
* Property: canvas
|
||||||
* {Canvas} The canvas context object.
|
* {Canvas} The canvas context object.
|
||||||
|
|||||||
@@ -331,12 +331,6 @@ OpenLayers.Renderer.Elements = OpenLayers.Class(OpenLayers.Renderer, {
|
|||||||
*/
|
*/
|
||||||
rendererRoot: null,
|
rendererRoot: null,
|
||||||
|
|
||||||
/**
|
|
||||||
* Property: root
|
|
||||||
* {DOMElement}
|
|
||||||
*/
|
|
||||||
root: null,
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Property: xmlns
|
* Property: xmlns
|
||||||
* {String}
|
* {String}
|
||||||
@@ -887,6 +881,36 @@ OpenLayers.Renderer.Elements = OpenLayers.Class(OpenLayers.Renderer, {
|
|||||||
*/
|
*/
|
||||||
createNode: function(type, id) {},
|
createNode: function(type, id) {},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method: moveRoot
|
||||||
|
* moves this renderer's root to a different renderer.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* renderer - {<OpenLayers.Renderer>} target renderer for the moved root
|
||||||
|
*/
|
||||||
|
moveRoot: function(renderer) {
|
||||||
|
var root = this.root;
|
||||||
|
if(renderer.root.parentNode == this.rendererRoot) {
|
||||||
|
root = renderer.root;
|
||||||
|
}
|
||||||
|
root.parentNode.removeChild(root);
|
||||||
|
renderer.rendererRoot.appendChild(root);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method: getRenderLayer
|
||||||
|
* Gets the layer that this renderer's output appears on. If moveRoot was
|
||||||
|
* used, this will be different from the layer containing the features
|
||||||
|
* rendered by this renderer.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* {<OpenLayers.Layer.Vector>} the output layer, if any (i.e. this method
|
||||||
|
* will not return a layer if it is not added to a map).
|
||||||
|
*/
|
||||||
|
getRenderLayer: function() {
|
||||||
|
return this.map.getLayer(this.root.parentNode.parentNode.id);
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method: isComplexSymbol
|
* Method: isComplexSymbol
|
||||||
* Determines if a symbol cannot be rendered using drawCircle
|
* Determines if a symbol cannot be rendered using drawCircle
|
||||||
|
|||||||
@@ -810,6 +810,26 @@ OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, {
|
|||||||
return node;
|
return node;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method: moveRoot
|
||||||
|
* moves this renderer's root to a different renderer.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* renderer - {<OpenLayers.Renderer>} target renderer for the moved root
|
||||||
|
* root - {DOMElement} optional root node. To be used when this renderer
|
||||||
|
* holds roots from multiple layers to tell this method which one to
|
||||||
|
* detach
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* {Boolean} true if successful, false otherwise
|
||||||
|
*/
|
||||||
|
moveRoot: function(renderer) {
|
||||||
|
var layer = this.map.getLayer(this.container.id);
|
||||||
|
layer && this.clear();
|
||||||
|
OpenLayers.Renderer.Elements.prototype.moveRoot.apply(this, arguments);
|
||||||
|
layer && layer.redraw();
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method: importSymbol
|
* Method: importSymbol
|
||||||
* add a new symbol definition from the rendererer's symbol hash
|
* add a new symbol definition from the rendererer's symbol hash
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<script src="../../lib/OpenLayers.js"></script>
|
<script src="../../lib/OpenLayers.js"></script>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
function test_Control_SelectFeature_constructor(t) {
|
function test_Control_SelectFeature_constructor(t) {
|
||||||
t.plan(2);
|
t.plan(3);
|
||||||
var options = {
|
var options = {
|
||||||
// geometryTypes: "foo"
|
// geometryTypes: "foo"
|
||||||
};
|
};
|
||||||
@@ -11,10 +11,11 @@
|
|||||||
var control = new OpenLayers.Control.SelectFeature(layer, options);
|
var control = new OpenLayers.Control.SelectFeature(layer, options);
|
||||||
t.ok(control instanceof OpenLayers.Control.SelectFeature,
|
t.ok(control instanceof OpenLayers.Control.SelectFeature,
|
||||||
"new OpenLayers.Control.SelectFeature returns an instance");
|
"new OpenLayers.Control.SelectFeature returns an instance");
|
||||||
t.eq(control.layer, "bar",
|
t.eq(control.layers[0], "bar",
|
||||||
"constructor sets layer correctly");
|
"constructor sets layer correctly");
|
||||||
// t.eq(control.handlers.feature.geometryTypes, "foo",
|
// t.eq(control.handlers.feature.geometryTypes, "foo",
|
||||||
// "constructor sets options correctly on feature handler");
|
// "constructor sets options correctly on feature handler");
|
||||||
|
t.ok(control.layer instanceof OpenLayers.Layer.Vector.RootContainer, "control has a root container layer");
|
||||||
}
|
}
|
||||||
|
|
||||||
function test_Control_SelectFeature_destroy(t) {
|
function test_Control_SelectFeature_destroy(t) {
|
||||||
@@ -37,20 +38,29 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function test_Control_SelectFeature_select(t) {
|
function test_Control_SelectFeature_select(t) {
|
||||||
t.plan(2);
|
t.plan(4);
|
||||||
var map = new OpenLayers.Map("map");
|
var map = new OpenLayers.Map("map");
|
||||||
var layer = new OpenLayers.Layer.Vector();
|
var layer1 = new OpenLayers.Layer.Vector();
|
||||||
map.addLayer(layer);
|
var layer2 = new OpenLayers.Layer.Vector();
|
||||||
var control = new OpenLayers.Control.SelectFeature(layer);
|
map.addLayers([layer1, layer2]);
|
||||||
var feature = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(0,0));
|
var control = new OpenLayers.Control.SelectFeature([layer1, layer2]);
|
||||||
layer.addFeatures(feature);
|
var feature1 = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(0,1));
|
||||||
layer.drawFeature = function(feature, style) {
|
var feature2 = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(1,0));
|
||||||
layer.styleMap.createSymbolizer(feature, style);
|
layer1.addFeatures(feature1);
|
||||||
|
layer2.addFeatures(feature2);
|
||||||
|
var drawFeature = function(feature, style) {
|
||||||
|
feature.layer.styleMap.createSymbolizer(feature, style);
|
||||||
}
|
}
|
||||||
control.select(feature);
|
layer1.drawFeature = drawFeature;
|
||||||
t.eq(feature.renderIntent, "select", "render intent is set to select");
|
layer2.drawFeature = drawFeature;
|
||||||
control.unselect(feature);
|
control.select(feature1);
|
||||||
t.eq(feature.renderIntent, "default", "render intent is set back to default");
|
t.eq(feature1.renderIntent, "select", "render intent is set to select");
|
||||||
|
control.select(feature2);
|
||||||
|
t.eq(feature2.renderIntent, "select", "render intent is set to select");
|
||||||
|
control.unselect(feature1);
|
||||||
|
t.eq(feature1.renderIntent, "default", "render intent is set back to default");
|
||||||
|
control.unselect(feature2);
|
||||||
|
t.eq(feature2.renderIntent, "default", "render intent is set back to default");
|
||||||
}
|
}
|
||||||
|
|
||||||
function test_Control_SelectFeature_clickFeature(t) {
|
function test_Control_SelectFeature_clickFeature(t) {
|
||||||
@@ -74,14 +84,15 @@
|
|||||||
features[i] = {
|
features[i] = {
|
||||||
id: Math.random(),
|
id: Math.random(),
|
||||||
tested: 0,
|
tested: 0,
|
||||||
style: ""
|
style: "",
|
||||||
|
layer: layer
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// test that onSelect gets called properly
|
// test that onSelect gets called properly
|
||||||
control.onSelect = function(feature) {
|
control.onSelect = function(feature) {
|
||||||
feature.tested += 1;
|
feature.tested += 1;
|
||||||
t.eq(feature, features[feature.index],
|
t.eq(feature.id, features[feature.index].id,
|
||||||
"onSelect called with proper feature (" + feature.index + ")");
|
"onSelect called with proper feature (" + feature.index + ")");
|
||||||
t.eq(feature.tested, feature.test,
|
t.eq(feature.tested, feature.test,
|
||||||
"onSelect called only once for feature (" + feature.index + ")");
|
"onSelect called only once for feature (" + feature.index + ")");
|
||||||
@@ -90,7 +101,7 @@
|
|||||||
// test that onUnselect gets called properly
|
// test that onUnselect gets called properly
|
||||||
control.onUnselect = function(feature) {
|
control.onUnselect = function(feature) {
|
||||||
feature.tested += 1;
|
feature.tested += 1;
|
||||||
t.eq(feature, features[feature.index],
|
t.eq(feature.id, features[feature.index].id,
|
||||||
"onUnselect called with proper feature (" + feature.index + ")");
|
"onUnselect called with proper feature (" + feature.index + ")");
|
||||||
t.eq(feature.tested, feature.test,
|
t.eq(feature.tested, feature.test,
|
||||||
"onUnselect called only once for feature (" + feature.index + ")");
|
"onUnselect called only once for feature (" + feature.index + ")");
|
||||||
|
|||||||
55
tests/Layer/Vector/RootContainer.html
Normal file
55
tests/Layer/Vector/RootContainer.html
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<script src="../../../lib/OpenLayers.js"></script>
|
||||||
|
<script type="text/javascript">
|
||||||
|
var layer, map;
|
||||||
|
|
||||||
|
function test_RootContainer_collectResetRoots(t) {
|
||||||
|
t.plan(4);
|
||||||
|
|
||||||
|
map = new OpenLayers.Map("map");
|
||||||
|
var layer1 = new OpenLayers.Layer.Vector("layer1");
|
||||||
|
var layer2 = new OpenLayers.Layer.Vector("layer2");
|
||||||
|
layer = new OpenLayers.Layer.Vector.RootContainer("layer_1_2", {
|
||||||
|
layers: [layer1, layer2]
|
||||||
|
});
|
||||||
|
|
||||||
|
// addLayers will call setMap() for layer, which will call collectRoots()
|
||||||
|
map.addLayers([layer1, layer2, layer]);
|
||||||
|
t.eq(layer.renderer.rendererRoot.childNodes.length, 3, "layer has correct number of renderer roots");
|
||||||
|
t.eq(layer1.renderer.rendererRoot.childNodes.length, 0, "layer1 has no own renderer root");
|
||||||
|
|
||||||
|
layer.resetRoots();
|
||||||
|
t.eq(layer.renderer.rendererRoot.childNodes.length, 1, "roots removed from container");
|
||||||
|
t.eq(layer1.renderer.rendererRoot.childNodes.length, 1, "root re-added to original layer");
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_RootContainer_getFeatureFromEvent(t) {
|
||||||
|
t.plan(2);
|
||||||
|
var map = new OpenLayers.Map("map");
|
||||||
|
var layer1 = new OpenLayers.Layer.Vector("layer1");
|
||||||
|
var layer2 = new OpenLayers.Layer.Vector("layer2");
|
||||||
|
layer = new OpenLayers.Layer.Vector.RootContainer("layer_1_2", {
|
||||||
|
layers: [layer1, layer2]
|
||||||
|
});
|
||||||
|
map.addLayers([layer1, layer2, layer]);
|
||||||
|
var feature1 = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(0,1));
|
||||||
|
var feature2 = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(1,0));
|
||||||
|
layer1.addFeatures(feature1);
|
||||||
|
layer2.addFeatures(feature2);
|
||||||
|
t.eq(layer.getFeatureFromEvent({
|
||||||
|
srcElement: {
|
||||||
|
_featureId: feature1.id
|
||||||
|
}
|
||||||
|
}).id, feature1.id, "feature from layer1 found");
|
||||||
|
t.eq(layer.getFeatureFromEvent({srcElement: {
|
||||||
|
_featureId: feature2.id
|
||||||
|
}}).id, feature2.id, "feature from layer2 found");
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="map" style="width:500px;height:550px"></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -466,7 +466,7 @@
|
|||||||
|
|
||||||
OpenLayers.Util.getElement = OpenLayers.Util._getElement;
|
OpenLayers.Util.getElement = OpenLayers.Util._getElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
function test_Elements_drawAndErase(t) {
|
function test_Elements_drawAndErase(t) {
|
||||||
t.plan(20);
|
t.plan(20);
|
||||||
|
|
||||||
@@ -543,6 +543,19 @@
|
|||||||
tearDown();
|
tearDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function test_Elements_moveRoot(t) {
|
||||||
|
t.plan(2);
|
||||||
|
setUp();
|
||||||
|
var r1 = create_renderer();
|
||||||
|
var r2 = create_renderer();
|
||||||
|
r1.moveRoot(r2);
|
||||||
|
t.xml_eq(r1.root.parentNode, r2.root.parentNode, "root moved successfully");
|
||||||
|
r1.moveRoot(r1);
|
||||||
|
t.xml_eq(r1.root.parentNode, r1.rendererRoot, "root moved back successfully");
|
||||||
|
tearDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
|
|||||||
@@ -115,6 +115,7 @@
|
|||||||
<li>Layer/TileCache.html</li>
|
<li>Layer/TileCache.html</li>
|
||||||
<li>Layer/TMS.html</li>
|
<li>Layer/TMS.html</li>
|
||||||
<li>Layer/Vector.html</li>
|
<li>Layer/Vector.html</li>
|
||||||
|
<li>Layer/Vector/RootContainer.html</li>
|
||||||
<li>Layer/WFS.html</li>
|
<li>Layer/WFS.html</li>
|
||||||
<li>Layer/WMS.html</li>
|
<li>Layer/WMS.html</li>
|
||||||
<li>Layer/WrapDateLine.html</li>
|
<li>Layer/WrapDateLine.html</li>
|
||||||
|
|||||||
Reference in New Issue
Block a user