Often when presenting users with an interactive map, it is useful to allow them to control the visible layers. In this tutorial, we examine the use of GeoExt.tree.LayerContainer with the stock Ext.tree.TreePanel class to accommodate toggling visibility of layers and rearranging their drawing order.
Note
Before starting this tutorial, you should have a working GeoExt.MapPanel in your page. The MapPanel Tutorial will help you set one up if you don’t already have one.
Let’s assume you already have a GeoExt.MapPanel on your page with some layers. In the MapPanel Tutorial, we discussed how you can use the layers property of the MapPanel to add, remove, and modify the layers of the map as well as monitor the layer list for changes. This is more than sufficient to display a ‘live’ list of layers in an Ext.grid.GridPanel. The GeoExt.tree.LayerContainer is another component that can listen to changes to the map’s layer list. However, rather than an independent panel, the LayerContainer is a node that must be contained in an Ext.tree.TreePanel to be displayed. Here’s an example rendering a layer tree to a div:
var mapPanel = new GeoExt.MapPanel({
/* Your configuration here */
});
var layerList = new GeoExt.tree.LayerContainer({
text: 'All Layers',
layerStore: mapPanel.layers,
leaf: false,
expanded: true
});
var layerTree = new Ext.tree.TreePanel({
title: 'Map Layers',
renderTo: 'layerTree',
root: layerList
});
LayerContainers automatically add checkboxes (radio buttons for base layers) that can be used to toggle the visibility of layers. You can also enable drag-n-drop layer reordering by simply setting the enableDD property of the TreePanel.
By default, the LayerContainer‘s LayerLoader automatically pulls in all layers from the store and displays those with the displayInLayerSwitcher property set to true. You can provide your own filter function to the loader:
var layerList = new GeoExt.tree.LayerContainer({
text: 'Tasmania Layers',
layerStore: mapPanel.layers,
leaf: false,
expanded: true,
loader: {
filter: function(record) {
return record.get("layer").name.indexOf("Tasmania") !== -1
}
}
});
The above will only load layers with “Tasmania” in their name. By adding multiple named and filtered LayerContainers to a TreePanel you are able to provide logical organization to your layer trees. When enableDD is set to true on the tree, drag-n-drop will also work between filtered layer containers, as long as they have the same parent node. You can also directly instantiate GeoExt.tree.LayerNode to create tree nodes that can be added anywhere in a tree. Keep in mind, however, that this approach does not allow for automatic drag-n-drop support.
Note
There are two LayerContainer types with a preconfigured filter:
The concept of a base layer in OpenLayers is just a group of layers that are on the bottom of the layer stack, and only one can be visible at a time. In maps without base layers (when allOverlays is set to true), the latter can be enforced by configuring a checkedGroup on a LayerNode. Such a layer node will be rendered with a radio button instead of a check box. Of all layers configured with the same checkedGroup, only one will be visible at a time:
var layerList = new GeoExt.tree.LayerContainer({
text: 'Tasmania Layers',
layerStore: mapPanel.layers,
leaf: false,
expanded: true,
loader: {
filter: function(record) {
return record.get("layer").name.indexOf("Tasmania") !== -1
},
baseAttrs: {
checkedGroup: "tasmania"
}
}
});
It is possible to render layer nodes with an additional radio button. This can be useful if an application uses the concept of an “active layer”. The active layer can then be set by clicking its radio button:
var layerList = new GeoExt.tree.LayerContainer({
text: 'All Layers',
layerStore: mapPanel.layers,
leaf: false,
expanded: true,
loader: {
baseAttrs: {
radioGroup: "active"
}
}
});
var registerRadio = function(node)
if(!node.hasListener("radiochange")) {
node.on("radiochange", function(node){
/* set your active layer here */
});
}
}
var layerTree = new Ext.tree.TreePanel({
title: 'Map Layers',
renderTo: 'layerTree',
root: layerList,
listeners: {
append: registerRadio,
insert: registerRadio
}
});
The layer node fires the “radiochange” event when the radio button is clicked. The above snippet configures a listener for this event when a node is added to or inserted in the tree.
Layers that have a params property (like OpenLayers.Layer.WMS) can be used to create sub-layers based on one of the params properties. This is useful to e.g. create sub-nodes from the layer object’s “LAYERS” or “CQL_FILTER” param:
var groupLayer = new OpenLayers.Layer.WMS("Tasmania (Group Layer)",
"http://demo.opengeo.org/geoserver/wms", {
layers: [
"topp:tasmania_state_boundaries",
"topp:tasmania_water_bodies",
"topp:tasmania_cities",
"topp:tasmania_roads"
],
transparent: true,
format: "image/gif"
}
);
var groupLayerNode = new GeoExt.tree.LayerNode({
layer: groupLayer,
leaf: false,
expanded: true,
loader: {
param: "LAYERS"
}
});
Note
The GeoExt.tree.LayerParamLoader does not add drag-n-drop support to the sub-nodes it creates, so allowDrag and allowDrag should be set to false for a GeoExt.tree.LayerNode configured with a GeoExt.class.LayerParamLoader, unless you provide custom “move” handlers.
See also
The ExtJS TreePanel documentation and examples for more information about customizing tree panels.