Ticket #2: LegendPanel.js
| File LegendPanel.js, 11.2 kB (added by bartvde, 2 years ago) |
|---|
| Line | |
|---|---|
| 1 | /* |
| 2 | * Copyright (C) 2008 Camptocamp, OpenGeo |
| 3 | * |
| 4 | * This file is part of GeoExt |
| 5 | * |
| 6 | * GeoExt is free software: you can redistribute it and/or modify |
| 7 | * it under the terms of the GNU General Public License as published by |
| 8 | * the Free Software Foundation, either version 3 of the License, or |
| 9 | * (at your option) any later version. |
| 10 | * |
| 11 | * GeoExt is distributed in the hope that it will be useful, |
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 14 | * GNU General Public License for more details. |
| 15 | * |
| 16 | * You should have received a copy of the GNU General Public License |
| 17 | * along with GeoExt. If not, see <http://www.gnu.org/licenses/>. |
| 18 | */ |
| 19 | |
| 20 | Ext.namespace('GeoExt', 'GeoExt.widgets'); |
| 21 | |
| 22 | /** |
| 23 | * Class: GeoExt.widgets.LegendPanel |
| 24 | * LegendPanel is an Ext.Panel that displays a legend for all layers in a |
| 25 | * map. Currently the following layers are supported: |
| 26 | * - {OpenLayers.Layer.WMS} |
| 27 | * In the future other layer types can be added. |
| 28 | * |
| 29 | * Inherits from: |
| 30 | * - {Ext.Panel} |
| 31 | */ |
| 32 | |
| 33 | /** |
| 34 | * Constructor: GeoExt.widgets.LegendPanel |
| 35 | * Create an instance of GeoExt.widgets.LegendPanel |
| 36 | * |
| 37 | * Parameters: |
| 38 | * config - {Object} A config object used to set the legend |
| 39 | * panel's properties. |
| 40 | * |
| 41 | * Returns: |
| 42 | * {<GeoExt.widgets.LegendPanel>} |
| 43 | */ |
| 44 | GeoExt.widgets.LegendPanel = function(config){ |
| 45 | Ext.apply(this, config); |
| 46 | GeoExt.widgets.LegendPanel.superclass.constructor.call(this); |
| 47 | } |
| 48 | |
| 49 | GeoExt.widgets.LegendPanel.LEGENDURL = 1; |
| 50 | GeoExt.widgets.LegendPanel.GETLEGENDGRAPHIC = 0; |
| 51 | |
| 52 | Ext.extend(GeoExt.widgets.LegendPanel, Ext.Panel, { |
| 53 | |
| 54 | /** |
| 55 | * APIProperty: wmsMode |
| 56 | * {Integer} should the legend component use SLD WMS GetLegendGraphic |
| 57 | * requests or LegendURLs from the GetCapabilities reponse? |
| 58 | * One of: GeoExt.widgets.LegendPanel.GETLEGENDGRAPHIC or |
| 59 | * GeoExt.widgets.LegendPanel.LEGENDURL. The LEGENDURL option requires |
| 60 | * the OpenLayers.Format.WMSCapabilities parser. GETLEGENDGRAPHIC is |
| 61 | * the default. |
| 62 | */ |
| 63 | wmsMode: GeoExt.widgets.LegendPanel.GETLEGENDGRAPHIC, |
| 64 | |
| 65 | /** |
| 66 | * APIProperty: map |
| 67 | * {OpenLayers.Map} |
| 68 | */ |
| 69 | map: null, |
| 70 | |
| 71 | /** |
| 72 | * APIProperty: labelCls |
| 73 | * {String} Additional css class to put on the legend labels |
| 74 | */ |
| 75 | labelCls: null, |
| 76 | |
| 77 | /** |
| 78 | * APIProperty: wmsLegendFormat |
| 79 | * {String} the format to use in the GetLegendGraphic requests, defaults |
| 80 | * to image/png. The value should be a valid mime-type. |
| 81 | */ |
| 82 | wmsLegendFormat: "image/png", |
| 83 | |
| 84 | /** |
| 85 | * APIProperty: ascending |
| 86 | * {Boolean} if true the layers in the tree will show the |
| 87 | * bottom OpenLayer layer on top and the top OpenLayer layer on the |
| 88 | * bottom. If false, this is inverted. |
| 89 | */ |
| 90 | ascending: true, |
| 91 | |
| 92 | /** |
| 93 | * APIProperty: static |
| 94 | * {Boolean} if true the LegendPanel will not listen to the addlayer, |
| 95 | * changelayer and removelayer events. So it will load with the initial |
| 96 | * state of the map object and not change anymore. |
| 97 | */ |
| 98 | static: false, |
| 99 | |
| 100 | /** |
| 101 | * Property: idPrefix |
| 102 | * {String} the prefix to use for the id attribute value of the sub panels |
| 103 | * (gxt for GeoExt and lp for LegendPanel) |
| 104 | */ |
| 105 | idPrefix: 'gxt-lp-', |
| 106 | |
| 107 | /** |
| 108 | * Method: initComponent |
| 109 | * Initialize this component. We register for the events here. |
| 110 | */ |
| 111 | initComponent: function() { |
| 112 | if (!this.static) { |
| 113 | this.map.events.register("addlayer", this, this.addLayer); |
| 114 | this.map.events.register("changelayer", this, this.changeLayer); |
| 115 | this.map.events.register("removelayer", this, this.removeLayer); |
| 116 | } |
| 117 | GeoExt.widgets.LegendPanel.superclass.initComponent.call(this); |
| 118 | }, |
| 119 | |
| 120 | /** |
| 121 | * Method: onRender |
| 122 | * This function is called when the component renders. |
| 123 | */ |
| 124 | onRender: function(ct, position) { |
| 125 | GeoExt.widgets.LegendPanel.superclass.onRender.call(this, ct, position); |
| 126 | var layers = this.map.layers.slice(); |
| 127 | if (!this.ascending) { |
| 128 | layers.reverse(); |
| 129 | } |
| 130 | for (var i=0, len=layers.length; i<len; i++) { |
| 131 | var layer = layers[i]; |
| 132 | this.createLegend(layer); |
| 133 | } |
| 134 | }, |
| 135 | |
| 136 | /** |
| 137 | * Method: onDestroy |
| 138 | * This function is called when the component destroys. We deregister |
| 139 | * the events here. |
| 140 | */ |
| 141 | onDestroy: function() { |
| 142 | if (!this.static) { |
| 143 | this.map.events.unregister("addlayer", this, this.addLayer); |
| 144 | this.map.events.unregister("changelayer", this, this.changeLayer); |
| 145 | this.map.events.unregister("removelayer", this, this.removeLayer); |
| 146 | } |
| 147 | GeoExt.widgets.LegendPanel.superclass.onDestroy.call(this); |
| 148 | }, |
| 149 | |
| 150 | /** |
| 151 | * Method: addLayer |
| 152 | * Internal function called on the addlayer event |
| 153 | * |
| 154 | * Parameters: |
| 155 | * evt - {Object} The event object sent by OpenLayers |
| 156 | */ |
| 157 | addLayer: function(evt) { |
| 158 | this.createLegend(evt.layer); |
| 159 | }, |
| 160 | |
| 161 | /** |
| 162 | * Method: removeLayer |
| 163 | * Internal function called on the removelayer event |
| 164 | * |
| 165 | * Parameters: |
| 166 | * evt - {Object} The event object sent by OpenLayers |
| 167 | */ |
| 168 | removeLayer: function(evt) { |
| 169 | if (evt.layer && evt.layer instanceof OpenLayers.Layer.WMS) { |
| 170 | this.remove(Ext.getCmp(this.generatePanelId(evt.layer))); |
| 171 | } |
| 172 | }, |
| 173 | |
| 174 | /** |
| 175 | * Method: changeLayer |
| 176 | * Internal function called on the changelayer event |
| 177 | * |
| 178 | * Parameters: |
| 179 | * evt - {Object} The event object sent by OpenLayers |
| 180 | */ |
| 181 | changeLayer: function(evt) { |
| 182 | // TODO deal with property order if we want to reflect the order |
| 183 | // in the legend |
| 184 | if (evt && evt.layer && evt.property) { |
| 185 | var panel = Ext.getCmp(this.generatePanelId(evt.layer)); |
| 186 | if (!panel) { |
| 187 | panel = this.createLegend(evt.layer); |
| 188 | } |
| 189 | if (evt.property == 'visibility') { |
| 190 | if (panel) { |
| 191 | panel.setVisible(evt.layer.getVisibility()); |
| 192 | } |
| 193 | } |
| 194 | // it is possible for an application to hide layers from the legend |
| 195 | // by setting the hideInLegend property on the layer |
| 196 | // when the hideInLegend property changes, the application is |
| 197 | // responsible for triggering a changelayer event with a property |
| 198 | // named legendvisibility. |
| 199 | else if (evt.property == 'legendvisibility') { |
| 200 | if (panel) { |
| 201 | panel.setVisible(!evt.layer.hideInLegend); |
| 202 | } |
| 203 | } |
| 204 | } |
| 205 | }, |
| 206 | |
| 207 | /** |
| 208 | * Method: generatePanelId |
| 209 | * Generate an id attribute value for the panel. |
| 210 | * It is assumed that the combination of layer.params.LAYER and |
| 211 | * layer.mame is unique. |
| 212 | * |
| 213 | * Parameters: |
| 214 | * layer - {<OpenLayers.Layer.WMS>} the layer object |
| 215 | * |
| 216 | * Returns: |
| 217 | * {String} |
| 218 | */ |
| 219 | generatePanelId: function(layer) { |
| 220 | return this.idPrefix + layer.params.LAYERS + layer.name; |
| 221 | }, |
| 222 | |
| 223 | /** |
| 224 | * Method: onImageLoadError |
| 225 | * When the image fails loading (e.g. when the server returns an XML |
| 226 | * exception) we need to set the src to a blank image otherwise IE |
| 227 | * will show the infamous red cross. |
| 228 | */ |
| 229 | onImageLoadError: function() { |
| 230 | this.src = Ext.BLANK_IMAGE_URL; |
| 231 | }, |
| 232 | |
| 233 | /** |
| 234 | * Method: createLegendPanel |
| 235 | * Create a panel for every layer, it will contain a Label with the |
| 236 | * layer's name and for every possible sub layer an image |
| 237 | * |
| 238 | * Parameters: |
| 239 | * id - {String} the unique id to use for the panel |
| 240 | * title - {String} the title of the layer |
| 241 | * legImg - {Object} the legend image object |
| 242 | * |
| 243 | * Returns: |
| 244 | * {<Ext.Panel>} |
| 245 | */ |
| 246 | createLegendPanel: function(id, title, legImg) { |
| 247 | // TODO: we probably need the ability to change the css class |
| 248 | // of the label |
| 249 | var panel = new Ext.Panel({ |
| 250 | id: id, |
| 251 | bodyStyle: this.bodyStyle, |
| 252 | items: [ |
| 253 | new Ext.form.Label({ |
| 254 | text: title, |
| 255 | cls: 'x-form-item x-form-item-label' + |
| 256 | (this.labelCls ? ' ' + this.labelCls : '') |
| 257 | }) |
| 258 | ] |
| 259 | }); |
| 260 | for (var i=0, len=legImg.length; i<len; i++) { |
| 261 | panel.add(new Ext.BoxComponent({el: legImg[i]})); |
| 262 | } |
| 263 | return panel; |
| 264 | }, |
| 265 | |
| 266 | /** |
| 267 | * Method: getLegendUrl |
| 268 | * Get the URL from which the legend image can be retrieved |
| 269 | * |
| 270 | * Parameters: |
| 271 | * layer - {<OpenLayers.Layer.WMS>} the WMS layer |
| 272 | * layerName - {String} one of the layers from the LAYERS parameter |
| 273 | * |
| 274 | * Returns: |
| 275 | * {String} |
| 276 | */ |
| 277 | getLegendUrl: function(layer, layerName) { |
| 278 | if (this.wmsMode == GeoExt.widgets.LegendPanel.GETLEGENDGRAPHIC) { |
| 279 | return layer.getFullRequestString({ |
| 280 | REQUEST: "GetLegendGraphic", |
| 281 | WIDTH: null, |
| 282 | HEIGHT: null, |
| 283 | EXCEPTIONS: "application/vnd.ogc.se_xml", |
| 284 | LAYER: layerName, |
| 285 | LAYERS: null, |
| 286 | SRS: null, |
| 287 | FORMAT: this.wmsLegendFormat |
| 288 | }); |
| 289 | } |
| 290 | }, |
| 291 | |
| 292 | /** |
| 293 | * Method: createImage |
| 294 | * Create an image object for the legend image |
| 295 | * |
| 296 | * Parameters: |
| 297 | * src - {String} the source of the image (url) |
| 298 | * id - {String} the id (prefix) for the image object |
| 299 | * |
| 300 | * Returns: |
| 301 | * {DOMElement} |
| 302 | */ |
| 303 | createImage: function(src, id) { |
| 304 | var legendImage = document.createElement("img"); |
| 305 | Ext.EventManager.addListener(legendImage, 'error', |
| 306 | this.onImageLoadError, legendImage); |
| 307 | legendImage.src = src; |
| 308 | legendImage.id = id+'_img'; |
| 309 | return legendImage; |
| 310 | }, |
| 311 | |
| 312 | /** |
| 313 | * Method: createLegend |
| 314 | * Create the legend panel for a layer |
| 315 | * |
| 316 | * Parameters: |
| 317 | * layer - {<OpenLayers.Layer>} the layer object |
| 318 | */ |
| 319 | createLegend: function(layer) { |
| 320 | // currently only OpenLayers.Layer.WMS is supported and |
| 321 | // only for visible layers a legend is created. |
| 322 | // If an application does not want a layer in the legend |
| 323 | // they can set hideInLegend to true on the layer. |
| 324 | var panel; |
| 325 | if (layer instanceof OpenLayers.Layer.WMS && |
| 326 | layer.getVisibility() && !layer.hideInLegend) { |
| 327 | // if LAYERS param is in the form of LAYERS=A,B,C we need to |
| 328 | //split them up, and show an image per layer |
| 329 | var layers = layer.params.LAYERS.split(","); |
| 330 | var legImg = []; |
| 331 | for (var i=0, len=layers.length; i<len; i++) { |
| 332 | var layerName = layers[i]; |
| 333 | legImg.push(this.createImage( |
| 334 | this.getLegendUrl(layer, layerName), |
| 335 | this.generatePanelId(layer)+i)); |
| 336 | } |
| 337 | panel = this.createLegendPanel(this.generatePanelId(layer), |
| 338 | layer.name, legImg); |
| 339 | if (this.ascending) { |
| 340 | this.add(panel); |
| 341 | } else { |
| 342 | var idx = (this.map.layers.length-1)-this.map.getLayerIndex(layer); |
| 343 | this.insert(idx, panel); |
| 344 | } |
| 345 | this.doLayout(); |
| 346 | } |
| 347 | return panel; |
| 348 | } |
| 349 | |
| 350 | }); |
| 351 | |
| 352 | Ext.reg('gx_legend', GeoExt.widgets.LegendPanel); |