1 | ============================ |
---|
2 | Layer Tree Tutorial |
---|
3 | ============================ |
---|
4 | |
---|
5 | Often when presenting users with an interactive map, it is useful to allow them |
---|
6 | to control the visible layers. In this tutorial, we examine the use of |
---|
7 | :class:`GeoExt.tree.LayerContainer` with the stock ``Ext.tree.TreePanel`` class |
---|
8 | to accommodate toggling visibility of layers and rearranging their drawing |
---|
9 | order. |
---|
10 | |
---|
11 | .. note:: Before starting this tutorial, you should have a working |
---|
12 | :class:`GeoExt.MapPanel` in your page. The :doc:`mappanel-tutorial` will |
---|
13 | help you set one up if you don't already have one. |
---|
14 | |
---|
15 | Start With a Map |
---|
16 | ================ |
---|
17 | |
---|
18 | Let's assume you already have a :class:`GeoExt.MapPanel` on your page with some |
---|
19 | layers. In the :doc:`mappanel-tutorial`\ , we discussed how you can use the |
---|
20 | ``layers`` property of the ``MapPanel`` to add, remove, and modify the layers of |
---|
21 | the map as well as monitor the layer list for changes. This is more than |
---|
22 | sufficient to display a 'live' list of layers in an ``Ext.grid.GridPanel``\ . |
---|
23 | The :class:`GeoExt.tree.LayerContainer` is another component that can listen to |
---|
24 | changes to the map's layer list. However, rather than an independent panel, the |
---|
25 | ``LayerContainer`` is a node that must be contained in an ``Ext.tree.TreePanel`` |
---|
26 | to be displayed. Here's an example rendering a layer tree to a ``div``: |
---|
27 | |
---|
28 | .. code-block:: javascript |
---|
29 | |
---|
30 | var mapPanel = new GeoExt.MapPanel({ |
---|
31 | /* Your configuration here */ |
---|
32 | }); |
---|
33 | |
---|
34 | var layerList = new GeoExt.tree.LayerContainer({ |
---|
35 | text: 'All Layers', |
---|
36 | layerStore: mapPanel.layers, |
---|
37 | leaf: false, |
---|
38 | expanded: true |
---|
39 | }); |
---|
40 | |
---|
41 | var layerTree = new Ext.tree.TreePanel({ |
---|
42 | title: 'Map Layers', |
---|
43 | renderTo: 'layerTree', |
---|
44 | root: layerList |
---|
45 | }); |
---|
46 | |
---|
47 | ``LayerContainer``\ s automatically add checkboxes (radio buttons for base |
---|
48 | layers) that can be used to toggle the visibility of layers. You can also enable |
---|
49 | drag-n-drop layer reordering by simply setting the ``enableDD`` property of the |
---|
50 | ``TreePanel``. |
---|
51 | |
---|
52 | Filtering |
---|
53 | ========= |
---|
54 | By default, the ``LayerContainer``'s ``LayerLoader`` automatically pulls in all layers from the store and displays those with the ``displayInLayerSwitcher`` |
---|
55 | property set to true. You can provide your own filter function to the loader: |
---|
56 | |
---|
57 | .. code-block:: javascript |
---|
58 | |
---|
59 | var layerList = new GeoExt.tree.LayerContainer({ |
---|
60 | text: 'Tasmania Layers', |
---|
61 | layerStore: mapPanel.layers, |
---|
62 | leaf: false, |
---|
63 | expanded: true, |
---|
64 | loader: { |
---|
65 | filter: function(record) { |
---|
66 | return record.get("layer").name.indexOf("Tasmania") !== -1 |
---|
67 | } |
---|
68 | } |
---|
69 | }); |
---|
70 | |
---|
71 | The above will only load layers with "Tasmania" in their name. By adding |
---|
72 | multiple named and filtered ``LayerContainer``\ s to a ``TreePanel`` you are |
---|
73 | able to provide logical organization to your layer trees. When ``enableDD`` is |
---|
74 | set to true on the tree, drag-n-drop will also work between filtered layer |
---|
75 | containers, as long as they have the same parent node. You can also directly |
---|
76 | instantiate :class:`GeoExt.tree.LayerNode` to create tree nodes that can be |
---|
77 | added anywhere in a tree. Keep in mind, however, that this approach does not |
---|
78 | allow for automatic drag-n-drop support. |
---|
79 | |
---|
80 | .. note:: |
---|
81 | |
---|
82 | There are two LayerContainer types with a preconfigured filter: |
---|
83 | |
---|
84 | * :class:`GeoExt.tree.BaseLayerContainer` will be populated only with layers |
---|
85 | that have isBaseLayer set to true, |
---|
86 | * :class:`GeoExt.tree.OverlayLayerContainer` will be populated only with |
---|
87 | layers that have isBaseLayer set to false. |
---|
88 | |
---|
89 | Visibility Grouping |
---|
90 | =================== |
---|
91 | |
---|
92 | The concept of a base layer in OpenLayers is just a gruop of layers that are on |
---|
93 | the bottom of the layer stack, and only one can be visible at a time. In maps |
---|
94 | without base layers (when ``allOverlays`` is set to true, the latter can be |
---|
95 | enforced by configuring a ``checkedGroup`` on a LayerNode. Such a layer node |
---|
96 | will be rendered with a radio button instead of a check box. Of all layers |
---|
97 | configured with the same ``checkedGroup``, only one will be visible at a time: |
---|
98 | |
---|
99 | .. code-block:: javascript |
---|
100 | |
---|
101 | var layerList = new GeoExt.tree.LayerContainer({ |
---|
102 | text: 'Tasmania Layers', |
---|
103 | layerStore: mapPanel.layers, |
---|
104 | leaf: false, |
---|
105 | expanded: true, |
---|
106 | loader: { |
---|
107 | filter: function(record) { |
---|
108 | return record.get("layer").name.indexOf("Tasmania") !== -1 |
---|
109 | }, |
---|
110 | baseAttrs: { |
---|
111 | checkedGroup: "tasmania" |
---|
112 | } |
---|
113 | } |
---|
114 | }); |
---|
115 | |
---|
116 | Layer Nodes with Additional Radio Buttons |
---|
117 | ========================================= |
---|
118 | |
---|
119 | It is possible to render layer nodes with an additional radio button. This can |
---|
120 | be useful if an application uses the concept of an "active layer". The active |
---|
121 | layer can then be set by clicking its radio button: |
---|
122 | |
---|
123 | .. code-block:: javascript |
---|
124 | |
---|
125 | var layerList = new GeoExt.tree.LayerContainer({ |
---|
126 | text: 'All Layers', |
---|
127 | layerStore: mapPanel.layers, |
---|
128 | leaf: false, |
---|
129 | expanded: true, |
---|
130 | loader: { |
---|
131 | baseAttrs: { |
---|
132 | radioGroup: "active" |
---|
133 | } |
---|
134 | } |
---|
135 | }); |
---|
136 | var registerRadio = function(node) |
---|
137 | if(!node.hasListener("radiochange")) { |
---|
138 | node.on("radiochange", function(node){ |
---|
139 | /* set your active layer here */ |
---|
140 | }); |
---|
141 | } |
---|
142 | } |
---|
143 | var layerTree = new Ext.tree.TreePanel({ |
---|
144 | title: 'Map Layers', |
---|
145 | renderTo: 'layerTree', |
---|
146 | root: layerList, |
---|
147 | listeners: { |
---|
148 | append: registerRadio, |
---|
149 | insert: registerRadio |
---|
150 | } |
---|
151 | }); |
---|
152 | |
---|
153 | The layer node fires the "radiochange" event when the radio button is clicked. |
---|
154 | The above snippet configures a listener for this event when a node is added to |
---|
155 | or inserted in the tree. |
---|
156 | |
---|
157 | Sub-Layers |
---|
158 | ========== |
---|
159 | |
---|
160 | Layers that have a ``params`` property (like ``OpenLayers.Layer.WMS``) can be |
---|
161 | used to create sub-layers based on one of the ``params`` properties. This is |
---|
162 | useful to e.g. create sub-nodes from the layer object's "LAYERS" or "CQL_FILTER" |
---|
163 | param: |
---|
164 | |
---|
165 | .. code-block:: javascript |
---|
166 | |
---|
167 | var groupLayer = new OpenLayers.Layer.WMS("Tasmania (Group Layer)", |
---|
168 | "http://demo.opengeo.org/geoserver/wms", { |
---|
169 | layers: [ |
---|
170 | "topp:tasmania_state_boundaries", |
---|
171 | "topp:tasmania_water_bodies", |
---|
172 | "topp:tasmania_cities", |
---|
173 | "topp:tasmania_roads" |
---|
174 | ], |
---|
175 | transparent: true, |
---|
176 | format: "image/gif" |
---|
177 | } |
---|
178 | ); |
---|
179 | var groupLayerNode = new GeoExt.tree.LayerNode({ |
---|
180 | layer: groupLayer, |
---|
181 | leaf: false, |
---|
182 | expanded: true, |
---|
183 | loader: { |
---|
184 | param: "LAYERS" |
---|
185 | } |
---|
186 | }); |
---|
187 | |
---|
188 | .. note:: |
---|
189 | The :class:`GeoExt.tree.LayerParamLoader` does not add drag-n-drop support |
---|
190 | to the sub-nodes it creates, so ``allowDrag`` and ``allowDrag`` should be |
---|
191 | set to false for a :class:`GeoExt.tree.LayerNode` configured with a |
---|
192 | :class:`GeoExt.class.LayerParamLoader`, unless you provide custom "move" |
---|
193 | handlers. |
---|
194 | |
---|
195 | .. seealso:: The ExtJS TreePanel `documentation |
---|
196 | <http://dev.sencha.com/deploy/dev/docs/?class=Ext.tree.TreePanel>`_ and `examples |
---|
197 | <http://dev.sencha.com/deploy/dev/examples/#sample-7>`_ for more |
---|
198 | information about customizing tree panels. |
---|