.. _geoext.layout.tree: Add a Tree to Manage the Map Layers =================================== In modern geo-web applications, layers visibility are often managed by using a tree. Unsurprisingly GeoExt provides all the required advanced features to build a layers tree. Add layers ---------- We currently have only one layer loaded in our map. Let's add some layers. Add a ``layers`` array to match the following. Note that it is pure OpenLayers code. .. code-block:: javascript var layers = [ new OpenLayers.Layer.WMS("Global Imagery", "http://maps.opengeo.org/geowebcache/service/wms", { layers: "bluemarble" }, { buffer: 0, visibility: false } ), new OpenLayers.Layer.WMS("Tasmania State Boundaries", "/geoserver/wms", { layers: "topp:tasmania_state_boundaries" }, { buffer: 0 } ), new OpenLayers.Layer.WMS("Water", "/geoserver/wms", { layers: "topp:tasmania_water_bodies", transparent: true, format: "image/gif" }, { isBaseLayer: false, buffer: 0 } ), new OpenLayers.Layer.WMS("Cities", "/geoserver/wms", { layers: "topp:tasmania_cities", transparent: true, format: "image/gif" }, { isBaseLayer: false, buffer: 0 } ), new OpenLayers.Layer.WMS("Tasmania Roads", "/geoserver/wms", { layers: "topp:tasmania_roads", transparent: true, format: "image/gif" }, { isBaseLayer: false, buffer: 0 } ) ]; Find the layers config option in the MapPanel definition in :file:`map.html` and replace it with the one above. Also, since we don't want all layers to be considered as overlays we need to set options for our map. Add the following to your `GeoExt.MapPanel` configuration object: .. code-block:: javascript map: {allOverlays: false} Layer Nodes and Containers -------------------------- In GeoExt, the way to display the list of layers in a tree is as simple as using a ``Ext.tree.TreePanel`` populated with nodes with a specific type. Several layer-aware node types are available. .. code-block:: javascript var tree = new Ext.tree.TreePanel({ root: {}, rootVisible: false }); tree.render(document.body); The simplest one is the ``GeoExt.tree.LayerNode``. It can be added anywhere in a tree, and it creates a tree node for a given layer. .. code-block:: javascript var node = new GeoExt.tree.LayerNode({ layer: "Tasmania Roads" }); tree.root.appendChild(node); With the code above, we created one checkbox for one OpenLayers Layer. We should be able to do the same for the other layers in our application. .. figure:: layout_tree_onelayer.png One layer node But instead of this, one can use helpers to do it in an easier way. By helpers, we mean containers. Containers are specific node types made to easily render layers as groups. The more generic one is ``GeoExt.tree.LayerContainer``. This container automatically pulls in `all` the layers from the map. In :file:`map.html` you can remove the code you used for the `LayerNode` and replace it by the following: .. code-block:: javascript var node = new GeoExt.tree.LayerContainer({ text: "All layers" }); tree.root.appendChild(node); .. figure:: layout_tree_simple.png a simple layer tree Two more containers are also available. They both extend the `LayerContainer` and are preconfigured with a specific 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. Replace the code above by the following: .. code-block:: javascript var node = new GeoExt.tree.BaseLayerContainer({ text: "Base Layers" }); tree.root.appendChild(node); var node = new GeoExt.tree.OverlayLayerContainer({ text: "Overlay Layers" }); tree.root.appendChild(node); The `BaseLayerContainer` is populated with nodes with a radio button whereas the `OverlayLayerContainer` is populated with nodes with a checkbox. Node Types ---------- In the same manner as `xtype` for components, one is invited to use shortcuts for node types. Respectively ``gx_layer``, ``gx_baselayercontainer`` and ``gx_overlaylayercontainer``. .. code-block:: javascript var layerList = [{ nodeType: "gx_baselayercontainer", text: "Base Layers" }, { nodeType: "gx_overlaylayercontainer", text: "Overlay Layers", expanded: true }]; var tree = new Ext.tree.TreePanel({ loader: new Ext.tree.TreeLoader({ applyLoader: false }), root: { children: layerList }, rootVisible: false }); tree.render(document.body); The `expanded` parameter allows you to expand tree when loaded. A ``Ext.tree.TreeLoader`` with a `applyLoader` param set to false is required to not interfer with loaders of nodes further down the tree hierarchy. Layer Groups ------------ In the above examples, we were managing several `OpenLayers` layers. Most of them are provided by the same WMS service. It could then be a good idea to get them grouped in a single `OpenLayers` layers. The code below is intended to replace the three latest layers in the `MapPanel` configuration in :file:`map.html`. .. code-block:: javascript new OpenLayers.Layer.WMS("Tasmania (Group Layer)", "/geoserver/wms", { layers: [ "topp:tasmania_water_bodies", "topp:tasmania_cities", "topp:tasmania_roads" ] }, { isBaseLayer: false } ) Updating the application in the browser, we now have only one checkbox for the group. Rather, we would now like to have one checkbox for each layer defined in the `layers` array. We'll be able to do it using the `LayerNode` we already used earlier, but this time giving a `loader` configuration with a `param` option which specifies the layer parameter to rely on. Here the ``OpenLayers.Layer.WMS`` layer parameter we want to rely on is the `LAYERS` parameter. The following code can be used to replace the `OverlayLayerContainer` code: .. code-block:: javascript { nodeType: "gx_layer", layer: 'Tasmania (Group Layer)', loader: { param: 'LAYERS' } } Let's reload the browser page and confirm that you now have a tree node with sub-nodes for water bodies, cities and roads. .. figure:: layout_tree_group.png Layer in a group