# GeoExt

### Navigation

- GeoExt »
- Tutorials »
- Layer Tree Tutorial

# Layer Tree Tutorial

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.

## Start With a Map

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
    });

`LayerContainer`s 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`.

## Filtering

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 `LayerContainer`s 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:

- `GeoExt.tree.BaseLayerContainer` will be populated only with layers that have isBaseLayer set to true,
- `GeoExt.tree.OverlayLayerContainer` will be populated only with layers that have isBaseLayer set to false.

## Visibility Grouping

The concept of a base layer in OpenLayers is just a gruop 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"
            }
        }
    });

## Layer Nodes with Additional Radio Buttons

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.

## Sub-Layers

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.

### Navigation

- index
- modules |
- next |
- previous |
- GeoExt »
- Tutorials »
- Layer Tree Tutorial