[76] | 1 | /** |
---|
| 2 | * Copyright (c) 2008-2010 The Open Source Geospatial Foundation |
---|
| 3 | * |
---|
| 4 | * Published under the BSD license. |
---|
| 5 | * See http://svn.geoext.org/core/trunk/geoext/license.txt for the full text |
---|
| 6 | * of the license. |
---|
| 7 | */ |
---|
| 8 | |
---|
| 9 | /** |
---|
| 10 | * @include GeoExt/widgets/FeatureRenderer.js |
---|
| 11 | * @requires GeoExt/widgets/LayerLegend.js |
---|
| 12 | */ |
---|
| 13 | |
---|
| 14 | /** api: (define) |
---|
| 15 | * module = GeoExt |
---|
| 16 | * class = VectorLegend |
---|
| 17 | */ |
---|
| 18 | |
---|
| 19 | /** api: (extends) |
---|
| 20 | * GeoExt/widgets/LayerLegend.js |
---|
| 21 | */ |
---|
| 22 | |
---|
| 23 | Ext.namespace('GeoExt'); |
---|
| 24 | |
---|
| 25 | /** api: constructor |
---|
| 26 | * .. class:: VectorLegend(config) |
---|
| 27 | * |
---|
| 28 | * Create a vector legend. |
---|
| 29 | */ |
---|
| 30 | GeoExt.VectorLegend = Ext.extend(GeoExt.LayerLegend, { |
---|
| 31 | |
---|
| 32 | /** api: config[layerRecord] |
---|
| 33 | * :class:`GeoExt.data.LayerRecord` |
---|
| 34 | * The record containing a vector layer that this legend will be based on. |
---|
| 35 | * One of ``layerRecord``, ``layer``, or ``rules`` must be specified in |
---|
| 36 | * the config. |
---|
| 37 | */ |
---|
| 38 | layerRecord: null, |
---|
| 39 | |
---|
| 40 | /** api: config[layer] |
---|
| 41 | * ``OpenLayers.Layer.Vector`` |
---|
| 42 | * The layer that this legend will be based on. One of ``layer``, |
---|
| 43 | * ``rules``, or ``layerRecord`` must be specified in the config. |
---|
| 44 | */ |
---|
| 45 | layer: null, |
---|
| 46 | |
---|
| 47 | /** api: config[rules] |
---|
| 48 | * ``Array(OpenLayers.Rule)`` |
---|
| 49 | * List of rules. One of ``rules``, ``layer``, or ``layerRecord`` must be |
---|
| 50 | * specified in the config. The ``symbolType`` property must also be |
---|
| 51 | * provided if only ``rules`` are given in the config. |
---|
| 52 | */ |
---|
| 53 | rules: null, |
---|
| 54 | |
---|
| 55 | /** api: config[symbolType] |
---|
| 56 | * ``String`` |
---|
| 57 | * The symbol type for legend swatches. Must be one of ``"Point"``, |
---|
| 58 | * ``"Line"``, or ``"Polygon"``. If not provided, the ``layer`` or |
---|
| 59 | * ``layerRecord`` config property must be specified, and the geometry type |
---|
| 60 | * of the first feature found on the layer will be used. If a rule does |
---|
| 61 | * not have a symbolizer for ``symbolType``, we look at the symbolizers |
---|
| 62 | * for the rule, and see if it has a ``"Point"``, ``"Line"`` or |
---|
| 63 | * ``"Polygon"`` symbolizer, which we use for rendering a swatch of the |
---|
| 64 | * respective geometry type. |
---|
| 65 | */ |
---|
| 66 | symbolType: null, |
---|
| 67 | |
---|
| 68 | /** api: config[untitledPrefix] |
---|
| 69 | * ``String`` |
---|
| 70 | * The prefix to use as a title for rules with no title or |
---|
| 71 | * name. Default is ``"Untitled "``. Prefix will be appended with a |
---|
| 72 | * number that corresponds to the index of the rule (1 for first rule). |
---|
| 73 | */ |
---|
| 74 | untitledPrefix: "Untitled ", |
---|
| 75 | |
---|
| 76 | /** api: config[clickableSymbol] |
---|
| 77 | * ``Boolean`` |
---|
| 78 | * Set cursor style to "pointer" for symbolizers. Register for |
---|
| 79 | * the ``symbolclick`` event to handle clicks. Note that click events |
---|
| 80 | * are fired regardless of this value. If ``false``, no cursor style will |
---|
| 81 | * be set. Default is ``false``. |
---|
| 82 | */ |
---|
| 83 | clickableSymbol: false, |
---|
| 84 | |
---|
| 85 | /** api: config[clickableTitle] |
---|
| 86 | * ``Boolean`` |
---|
| 87 | * Set cursor style to "pointer" for rule titles. Register for |
---|
| 88 | * the ``titleclick`` event to handle clicks. Note that click events |
---|
| 89 | * are fired regardless of this value. If ``false``, no cursor style will |
---|
| 90 | * be set. Default is ``false``. |
---|
| 91 | */ |
---|
| 92 | clickableTitle: false, |
---|
| 93 | |
---|
| 94 | /** api: config[selectOnClick] |
---|
| 95 | * ``Boolean`` |
---|
| 96 | * Set to true if a rule should be selected by clicking on the |
---|
| 97 | * symbol or title. Selection will trigger the ruleselected event, and |
---|
| 98 | * a click on a selected rule will unselect it and trigger the |
---|
| 99 | * ``ruleunselected`` event. Default is ``false``. |
---|
| 100 | */ |
---|
| 101 | selectOnClick: false, |
---|
| 102 | |
---|
| 103 | /** api: config[enableDD] |
---|
| 104 | * ``Boolean`` |
---|
| 105 | * Allow drag and drop of rules. Default is ``false``. |
---|
| 106 | */ |
---|
| 107 | enableDD: false, |
---|
| 108 | |
---|
| 109 | /** api: config[bodyBorder] |
---|
| 110 | * ``Boolean`` |
---|
| 111 | * Show a border around the legend panel. Default is ``false``. |
---|
| 112 | */ |
---|
| 113 | bodyBorder: false, |
---|
| 114 | |
---|
| 115 | /** private: property[feature] |
---|
| 116 | * ``OpenLayers.Feature.Vector`` |
---|
| 117 | * Cached feature for rendering. |
---|
| 118 | */ |
---|
| 119 | feature: null, |
---|
| 120 | |
---|
| 121 | /** private: property[selectedRule] |
---|
| 122 | * ``OpenLayers.Rule`` |
---|
| 123 | * The rule that is currently selected. |
---|
| 124 | */ |
---|
| 125 | selectedRule: null, |
---|
| 126 | |
---|
| 127 | /** private: property[currentScaleDenominator] |
---|
| 128 | * ``Number`` |
---|
| 129 | * The current scale denominator of any map associated with this |
---|
| 130 | * legend. Use :meth`setCurrentScaleDenominator` to change this. If not |
---|
| 131 | * set an entry for each rule will be rendered. If set, only rules that |
---|
| 132 | * apply for the given scale will be rendered. |
---|
| 133 | */ |
---|
| 134 | currentScaleDenominator: null, |
---|
| 135 | |
---|
| 136 | /** private: method[initComponent] |
---|
| 137 | * Initializes the Vector legend. |
---|
| 138 | */ |
---|
| 139 | initComponent: function() { |
---|
| 140 | GeoExt.VectorLegend.superclass.initComponent.call(this); |
---|
| 141 | if (this.layerRecord) { |
---|
| 142 | this.layer = this.layerRecord.getLayer(); |
---|
| 143 | if (this.layer.map) { |
---|
| 144 | this.currentScaleDenominator = this.layer.map.getScale(); |
---|
| 145 | this.layer.map.events.on({ |
---|
| 146 | "zoomend": this.onMapZoom, |
---|
| 147 | scope: this |
---|
| 148 | }); |
---|
| 149 | } |
---|
| 150 | } |
---|
| 151 | |
---|
| 152 | // determine symbol type |
---|
| 153 | if (!this.symbolType) { |
---|
| 154 | if (this.feature) { |
---|
| 155 | this.symbolType = this.symbolTypeFromFeature(this.feature); |
---|
| 156 | } else if (this.layer) { |
---|
| 157 | if (this.layer.features.length > 0) { |
---|
| 158 | var feature = this.layer.features[0].clone(); |
---|
| 159 | feature.attributes = {}; |
---|
| 160 | this.feature = feature; |
---|
| 161 | this.symbolType = this.symbolTypeFromFeature(this.feature); |
---|
| 162 | } else { |
---|
| 163 | this.layer.events.on({ |
---|
| 164 | featuresadded: this.onFeaturesAdded, |
---|
| 165 | scope: this |
---|
| 166 | }); |
---|
| 167 | } |
---|
| 168 | } |
---|
| 169 | } |
---|
| 170 | |
---|
| 171 | // set rules if not provided |
---|
| 172 | if (this.layer && this.feature && !this.rules) { |
---|
| 173 | this.setRules(); |
---|
| 174 | } |
---|
| 175 | |
---|
| 176 | this.rulesContainer = new Ext.Container({ |
---|
| 177 | autoEl: {} |
---|
| 178 | }); |
---|
| 179 | |
---|
| 180 | this.add(this.rulesContainer); |
---|
| 181 | |
---|
| 182 | this.addEvents( |
---|
| 183 | /** api: event[titleclick] |
---|
| 184 | * Fires when a rule title is clicked. |
---|
| 185 | * |
---|
| 186 | * Listener arguments: |
---|
| 187 | * |
---|
| 188 | * * comp - :class:`GeoExt.VectorLegend`` This component. |
---|
| 189 | * * rule - ``OpenLayers.Rule`` The rule whose title was clicked. |
---|
| 190 | */ |
---|
| 191 | "titleclick", |
---|
| 192 | |
---|
| 193 | /** api: event[symbolclick] |
---|
| 194 | * Fires when a rule symbolizer is clicked. |
---|
| 195 | * |
---|
| 196 | * Listener arguments: |
---|
| 197 | * |
---|
| 198 | * * comp - :class:`GeoExt.VectorLegend`` This component. |
---|
| 199 | * * rule - ``OpenLayers.Rule`` The rule whose symbol was clicked. |
---|
| 200 | */ |
---|
| 201 | "symbolclick", |
---|
| 202 | |
---|
| 203 | /** api: event[ruleclick] |
---|
| 204 | * Fires when a rule entry is clicked (fired with symbolizer or |
---|
| 205 | * title click). |
---|
| 206 | * |
---|
| 207 | * Listener arguments: |
---|
| 208 | * |
---|
| 209 | * * comp - :class:`GeoExt.VectorLegend`` This component. |
---|
| 210 | * * rule - ``OpenLayers.Rule`` The rule that was clicked. |
---|
| 211 | */ |
---|
| 212 | "ruleclick", |
---|
| 213 | |
---|
| 214 | /** api: event[ruleselected] |
---|
| 215 | * Fires when a rule is clicked and ``selectOnClick`` is set to |
---|
| 216 | * ``true``. |
---|
| 217 | * |
---|
| 218 | * Listener arguments: |
---|
| 219 | * |
---|
| 220 | * * comp - :class:`GeoExt.VectorLegend`` This component. |
---|
| 221 | * * rule - ``OpenLayers.Rule`` The rule that was selected. |
---|
| 222 | */ |
---|
| 223 | "ruleselected", |
---|
| 224 | |
---|
| 225 | /** api: event[ruleunselected] |
---|
| 226 | * Fires when the selected rule is clicked and ``selectOnClick`` |
---|
| 227 | * is set to ``true``, or when a rule is unselected by selecting a |
---|
| 228 | * different one. |
---|
| 229 | * |
---|
| 230 | * Listener arguments: |
---|
| 231 | * |
---|
| 232 | * * comp - :class:`GeoExt.VectorLegend`` This component. |
---|
| 233 | * * rule - ``OpenLayers.Rule`` The rule that was unselected. |
---|
| 234 | */ |
---|
| 235 | "ruleunselected", |
---|
| 236 | |
---|
| 237 | /** api: event[rulemoved] |
---|
| 238 | * Fires when a rule is moved. |
---|
| 239 | * |
---|
| 240 | * Listener arguments: |
---|
| 241 | * |
---|
| 242 | * * comp - :class:`GeoExt.VectorLegend`` This component. |
---|
| 243 | * * rule - ``OpenLayers.Rule`` The rule that was moved. |
---|
| 244 | */ |
---|
| 245 | "rulemoved" |
---|
| 246 | ); |
---|
| 247 | |
---|
| 248 | this.update(); |
---|
| 249 | }, |
---|
| 250 | |
---|
| 251 | /** private: method[onMapZoom] |
---|
| 252 | * Listener for map zoomend. |
---|
| 253 | */ |
---|
| 254 | onMapZoom: function() { |
---|
| 255 | this.setCurrentScaleDenominator( |
---|
| 256 | this.layer.map.getScale() |
---|
| 257 | ); |
---|
| 258 | }, |
---|
| 259 | |
---|
| 260 | /** private: method[symbolTypeFromFeature] |
---|
| 261 | * :arg feature: ``OpenLayers.Feature.Vector`` |
---|
| 262 | * |
---|
| 263 | * Determine the symbol type given a feature. |
---|
| 264 | */ |
---|
| 265 | symbolTypeFromFeature: function(feature) { |
---|
| 266 | var match = feature.geometry.CLASS_NAME.match(/Point|Line|Polygon/); |
---|
| 267 | return (match && match[0]) || "Point"; |
---|
| 268 | }, |
---|
| 269 | |
---|
| 270 | /** private: method[onFeaturesAdded] |
---|
| 271 | * Set as a one time listener for the ``featuresadded`` event on the layer |
---|
| 272 | * if it was provided with no features originally. |
---|
| 273 | */ |
---|
| 274 | onFeaturesAdded: function() { |
---|
| 275 | this.layer.events.un({ |
---|
| 276 | featuresadded: this.onFeaturesAdded, |
---|
| 277 | scope: this |
---|
| 278 | }); |
---|
| 279 | var feature = this.layer.features[0].clone(); |
---|
| 280 | feature.attributes = {}; |
---|
| 281 | this.feature = feature; |
---|
| 282 | this.symbolType = this.symbolTypeFromFeature(this.feature); |
---|
| 283 | if (!this.rules) { |
---|
| 284 | this.setRules(); |
---|
| 285 | } |
---|
| 286 | this.update(); |
---|
| 287 | }, |
---|
| 288 | |
---|
| 289 | /** private: method[setRules] |
---|
| 290 | * Sets the ``rules`` property for this. This is called when the component |
---|
| 291 | * is constructed without rules. Rules will be derived from the layer's |
---|
| 292 | * style map if it has one. |
---|
| 293 | */ |
---|
| 294 | setRules: function() { |
---|
| 295 | var style = this.layer.styleMap && this.layer.styleMap.styles["default"]; |
---|
| 296 | if (!style) { |
---|
| 297 | style = new OpenLayers.Style(); |
---|
| 298 | } |
---|
| 299 | if (style.rules.length === 0) { |
---|
| 300 | this.rules = [ |
---|
| 301 | new OpenLayers.Rule({ |
---|
| 302 | symbolizer: style.createSymbolizer(this.feature) |
---|
| 303 | }) |
---|
| 304 | ]; |
---|
| 305 | } else { |
---|
| 306 | this.rules = style.rules; |
---|
| 307 | } |
---|
| 308 | }, |
---|
| 309 | |
---|
| 310 | /** api: method[setCurrentScaleDenominator] |
---|
| 311 | * :arg scale: ``Number`` The scale denominator. |
---|
| 312 | * |
---|
| 313 | * Set the current scale denominator. This will hide entries for any |
---|
| 314 | * rules that don't apply at the current scale. |
---|
| 315 | */ |
---|
| 316 | setCurrentScaleDenominator: function(scale) { |
---|
| 317 | if (scale !== this.currentScaleDenominator) { |
---|
| 318 | this.currentScaleDenominator = scale; |
---|
| 319 | this.update(); |
---|
| 320 | } |
---|
| 321 | }, |
---|
| 322 | |
---|
| 323 | /** private: method[getRuleEntry] |
---|
| 324 | * :arg rule: ``OpenLayers.Rule`` |
---|
| 325 | * :returns: ``Ext.Container`` |
---|
| 326 | * |
---|
| 327 | * Get the item corresponding to the rule. |
---|
| 328 | */ |
---|
| 329 | getRuleEntry: function(rule) { |
---|
| 330 | return this.rulesContainer.items.get(this.rules.indexOf(rule)); |
---|
| 331 | }, |
---|
| 332 | |
---|
| 333 | /** private: method[addRuleEntry] |
---|
| 334 | * :arg rule: ``OpenLayers.Rule`` |
---|
| 335 | * :arg noDoLayout: ``Boolean`` Don't call doLayout after adding rule. |
---|
| 336 | * Default is ``false``. |
---|
| 337 | * |
---|
| 338 | * Add a new rule entry in the rules container. This |
---|
| 339 | * method does not add the rule to the rules array. |
---|
| 340 | */ |
---|
| 341 | addRuleEntry: function(rule, noDoLayout) { |
---|
| 342 | this.rulesContainer.add(this.createRuleEntry(rule)); |
---|
| 343 | if (!noDoLayout) { |
---|
| 344 | this.doLayout(); |
---|
| 345 | } |
---|
| 346 | }, |
---|
| 347 | |
---|
| 348 | /** private: method[removeRuleEntry] |
---|
| 349 | * :arg rule: ``OpenLayers.Rule`` |
---|
| 350 | * :arg noDoLayout: ``Boolean`` Don't call doLayout after removing rule. |
---|
| 351 | * Default is ``false``. |
---|
| 352 | * |
---|
| 353 | * Remove a rule entry from the rules container, this |
---|
| 354 | * method assumes the rule is in the rules array, and |
---|
| 355 | * it does not remove the rule from the rules array. |
---|
| 356 | */ |
---|
| 357 | removeRuleEntry: function(rule, noDoLayout) { |
---|
| 358 | var ruleEntry = this.getRuleEntry(rule); |
---|
| 359 | if (ruleEntry) { |
---|
| 360 | this.rulesContainer.remove(ruleEntry); |
---|
| 361 | if (!noDoLayout) { |
---|
| 362 | this.doLayout(); |
---|
| 363 | } |
---|
| 364 | } |
---|
| 365 | }, |
---|
| 366 | |
---|
| 367 | /** private: method[selectRuleEntry] |
---|
| 368 | */ |
---|
| 369 | selectRuleEntry: function(rule) { |
---|
| 370 | var newSelection = rule != this.selectedRule; |
---|
| 371 | if (this.selectedRule) { |
---|
| 372 | this.unselect(); |
---|
| 373 | } |
---|
| 374 | if (newSelection) { |
---|
| 375 | var ruleEntry = this.getRuleEntry(rule); |
---|
| 376 | ruleEntry.body.addClass("x-grid3-row-selected"); |
---|
| 377 | this.selectedRule = rule; |
---|
| 378 | this.fireEvent("ruleselected", this, rule); |
---|
| 379 | } |
---|
| 380 | }, |
---|
| 381 | |
---|
| 382 | /** private: method[unselect] |
---|
| 383 | */ |
---|
| 384 | unselect: function() { |
---|
| 385 | this.rulesContainer.items.each(function(item, i) { |
---|
| 386 | if (this.rules[i] == this.selectedRule) { |
---|
| 387 | item.body.removeClass("x-grid3-row-selected"); |
---|
| 388 | this.selectedRule = null; |
---|
| 389 | this.fireEvent("ruleunselected", this, this.rules[i]); |
---|
| 390 | } |
---|
| 391 | }, this); |
---|
| 392 | }, |
---|
| 393 | |
---|
| 394 | /** private: method[createRuleEntry] |
---|
| 395 | */ |
---|
| 396 | createRuleEntry: function(rule) { |
---|
| 397 | var applies = true; |
---|
| 398 | if (this.currentScaleDenominator != null) { |
---|
| 399 | if (rule.minScaleDenominator) { |
---|
| 400 | applies = applies && (this.currentScaleDenominator >= rule.minScaleDenominator); |
---|
| 401 | } |
---|
| 402 | if (rule.maxScaleDenominator) { |
---|
| 403 | applies = applies && (this.currentScaleDenominator < rule.maxScaleDenominator); |
---|
| 404 | } |
---|
| 405 | } |
---|
| 406 | return { |
---|
| 407 | xtype: "panel", |
---|
| 408 | layout: "column", |
---|
| 409 | border: false, |
---|
| 410 | hidden: !applies, |
---|
| 411 | bodyStyle: this.selectOnClick ? {cursor: "pointer"} : undefined, |
---|
| 412 | defaults: { |
---|
| 413 | border: false |
---|
| 414 | }, |
---|
| 415 | items: [ |
---|
| 416 | this.createRuleRenderer(rule), |
---|
| 417 | this.createRuleTitle(rule) |
---|
| 418 | ], |
---|
| 419 | listeners: { |
---|
| 420 | render: function(comp){ |
---|
| 421 | this.selectOnClick && comp.getEl().on({ |
---|
| 422 | click: function(comp){ |
---|
| 423 | this.selectRuleEntry(rule); |
---|
| 424 | }, |
---|
| 425 | scope: this |
---|
| 426 | }); |
---|
| 427 | if (this.enableDD == true) { |
---|
| 428 | this.addDD(comp); |
---|
| 429 | } |
---|
| 430 | }, |
---|
| 431 | scope: this |
---|
| 432 | } |
---|
| 433 | }; |
---|
| 434 | }, |
---|
| 435 | |
---|
| 436 | /** private: method[createRuleRenderer] |
---|
| 437 | * :arg rule: ``OpenLayers.Rule`` |
---|
| 438 | * :returns: ``GeoExt.FeatureRenderer`` |
---|
| 439 | * |
---|
| 440 | * Create a renderer for the rule. |
---|
| 441 | */ |
---|
| 442 | createRuleRenderer: function(rule) { |
---|
| 443 | var types = [this.symbolType, "Point", "Line", "Polygon"]; |
---|
| 444 | var type, haveType; |
---|
| 445 | var symbolizers = rule.symbolizers; |
---|
| 446 | if (!symbolizers) { |
---|
| 447 | // TODO: remove this when OpenLayers.Symbolizer is used everywhere |
---|
| 448 | var symbolizer = rule.symbolizer; |
---|
| 449 | for (var i=0, len=types.length; i<len; ++i) { |
---|
| 450 | type = types[i]; |
---|
| 451 | if (symbolizer[type]) { |
---|
| 452 | symbolizer = symbolizer[type]; |
---|
| 453 | haveType = true; |
---|
| 454 | break; |
---|
| 455 | } |
---|
| 456 | } |
---|
| 457 | symbolizers = [symbolizer]; |
---|
| 458 | } else { |
---|
| 459 | var Type; |
---|
| 460 | outer: for (var i=0, ii=types.length; i<ii; ++i) { |
---|
| 461 | type = types[i]; |
---|
| 462 | Type = OpenLayers.Symbolizer[type]; |
---|
| 463 | if (Type) { |
---|
| 464 | for (var j=0, jj=symbolizers.length; j<jj; ++j) { |
---|
| 465 | if (symbolizers[j] instanceof Type) { |
---|
| 466 | haveType = true; |
---|
| 467 | break outer; |
---|
| 468 | } |
---|
| 469 | } |
---|
| 470 | } |
---|
| 471 | } |
---|
| 472 | } |
---|
| 473 | return { |
---|
| 474 | xtype: "gx_renderer", |
---|
| 475 | symbolType: haveType ? type : this.symbolType, |
---|
| 476 | symbolizers: symbolizers, |
---|
| 477 | style: this.clickableSymbol ? {cursor: "pointer"} : undefined, |
---|
| 478 | listeners: { |
---|
| 479 | click: function() { |
---|
| 480 | if (this.clickableSymbol) { |
---|
| 481 | this.fireEvent("symbolclick", this, rule); |
---|
| 482 | this.fireEvent("ruleclick", this, rule); |
---|
| 483 | } |
---|
| 484 | }, |
---|
| 485 | scope: this |
---|
| 486 | } |
---|
| 487 | }; |
---|
| 488 | }, |
---|
| 489 | |
---|
| 490 | /** private: method[createRuleTitle] |
---|
| 491 | * :arg rule: ``OpenLayers.Rule`` |
---|
| 492 | * :returns: ``Ext.Component`` |
---|
| 493 | * |
---|
| 494 | * Create a title component for the rule. |
---|
| 495 | */ |
---|
| 496 | createRuleTitle: function(rule) { |
---|
| 497 | return { |
---|
| 498 | cls: "x-form-item", |
---|
| 499 | style: "padding: 0.2em 0.5em 0;", // TODO: css |
---|
| 500 | bodyStyle: Ext.applyIf({background: "transparent"}, |
---|
| 501 | this.clickableTitle ? {cursor: "pointer"} : undefined), |
---|
| 502 | html: this.getRuleTitle(rule), |
---|
| 503 | listeners: { |
---|
| 504 | render: function(comp) { |
---|
| 505 | this.clickableTitle && comp.getEl().on({ |
---|
| 506 | click: function() { |
---|
| 507 | this.fireEvent("titleclick", this, rule); |
---|
| 508 | this.fireEvent("ruleclick", this, rule); |
---|
| 509 | }, |
---|
| 510 | scope: this |
---|
| 511 | }); |
---|
| 512 | }, |
---|
| 513 | scope: this |
---|
| 514 | } |
---|
| 515 | }; |
---|
| 516 | }, |
---|
| 517 | |
---|
| 518 | /** private: method[addDD] |
---|
| 519 | * :arg component: ``Ext.Component`` |
---|
| 520 | * |
---|
| 521 | * Adds drag & drop functionality to a rule entry. |
---|
| 522 | */ |
---|
| 523 | addDD: function(component) { |
---|
| 524 | var ct = component.ownerCt; |
---|
| 525 | var panel = this; |
---|
| 526 | new Ext.dd.DragSource(component.getEl(), { |
---|
| 527 | ddGroup: ct.id, |
---|
| 528 | onDragOut: function(e, targetId) { |
---|
| 529 | var target = Ext.getCmp(targetId); |
---|
| 530 | target.removeClass("gx-ruledrag-insert-above"); |
---|
| 531 | target.removeClass("gx-ruledrag-insert-below"); |
---|
| 532 | return Ext.dd.DragZone.prototype.onDragOut.apply(this, arguments); |
---|
| 533 | }, |
---|
| 534 | onDragEnter: function(e, targetId) { |
---|
| 535 | var target = Ext.getCmp(targetId); |
---|
| 536 | var cls; |
---|
| 537 | var sourcePos = ct.items.indexOf(component); |
---|
| 538 | var targetPos = ct.items.indexOf(target); |
---|
| 539 | if (sourcePos > targetPos) { |
---|
| 540 | cls = "gx-ruledrag-insert-above"; |
---|
| 541 | } else if (sourcePos < targetPos) { |
---|
| 542 | cls = "gx-ruledrag-insert-below"; |
---|
| 543 | } |
---|
| 544 | cls && target.addClass(cls); |
---|
| 545 | return Ext.dd.DragZone.prototype.onDragEnter.apply(this, arguments); |
---|
| 546 | }, |
---|
| 547 | onDragDrop: function(e, targetId) { |
---|
| 548 | panel.moveRule(ct.items.indexOf(component), |
---|
| 549 | ct.items.indexOf(Ext.getCmp(targetId))); |
---|
| 550 | return Ext.dd.DragZone.prototype.onDragDrop.apply(this, arguments); |
---|
| 551 | }, |
---|
| 552 | getDragData: function(e) { |
---|
| 553 | var sourceEl = e.getTarget(".x-column-inner"); |
---|
| 554 | if(sourceEl) { |
---|
| 555 | var d = sourceEl.cloneNode(true); |
---|
| 556 | d.id = Ext.id(); |
---|
| 557 | return { |
---|
| 558 | sourceEl: sourceEl, |
---|
| 559 | repairXY: Ext.fly(sourceEl).getXY(), |
---|
| 560 | ddel: d |
---|
| 561 | } |
---|
| 562 | } |
---|
| 563 | } |
---|
| 564 | }); |
---|
| 565 | new Ext.dd.DropTarget(component.getEl(), { |
---|
| 566 | ddGroup: ct.id, |
---|
| 567 | notifyDrop: function() { |
---|
| 568 | return true; |
---|
| 569 | } |
---|
| 570 | }); |
---|
| 571 | }, |
---|
| 572 | |
---|
| 573 | /** api: method[update] |
---|
| 574 | * Update rule titles and symbolizers. |
---|
| 575 | */ |
---|
| 576 | update: function() { |
---|
| 577 | GeoExt.VectorLegend.superclass.update.apply(this, arguments); |
---|
| 578 | if (this.symbolType && this.rules) { |
---|
| 579 | if (this.rulesContainer.items) { |
---|
| 580 | var comp; |
---|
| 581 | for (var i=this.rulesContainer.items.length-1; i>=0; --i) { |
---|
| 582 | comp = this.rulesContainer.getComponent(i); |
---|
| 583 | this.rulesContainer.remove(comp, true); |
---|
| 584 | } |
---|
| 585 | } |
---|
| 586 | for (var i=0, ii=this.rules.length; i<ii; ++i) { |
---|
| 587 | this.addRuleEntry(this.rules[i], true); |
---|
| 588 | } |
---|
| 589 | this.doLayout(); |
---|
| 590 | // make sure that the selected rule is still selected after update |
---|
| 591 | if (this.selectedRule) { |
---|
| 592 | this.getRuleEntry(this.selectedRule).body.addClass("x-grid3-row-selected"); |
---|
| 593 | } |
---|
| 594 | } |
---|
| 595 | }, |
---|
| 596 | |
---|
| 597 | /** private: method[updateRuleEntry] |
---|
| 598 | * :arg rule: ``OpenLayers.Rule`` |
---|
| 599 | * |
---|
| 600 | * Update the renderer and the title of a rule. |
---|
| 601 | */ |
---|
| 602 | updateRuleEntry: function(rule) { |
---|
| 603 | var ruleEntry = this.getRuleEntry(rule); |
---|
| 604 | if (ruleEntry) { |
---|
| 605 | ruleEntry.removeAll(); |
---|
| 606 | ruleEntry.add(this.createRuleRenderer(rule)); |
---|
| 607 | ruleEntry.add(this.createRuleTitle(rule)); |
---|
| 608 | ruleEntry.doLayout(); |
---|
| 609 | } |
---|
| 610 | }, |
---|
| 611 | |
---|
| 612 | /** private: method[moveRule] |
---|
| 613 | */ |
---|
| 614 | moveRule: function(sourcePos, targetPos) { |
---|
| 615 | var srcRule = this.rules[sourcePos]; |
---|
| 616 | this.rules.splice(sourcePos, 1); |
---|
| 617 | this.rules.splice(targetPos, 0, srcRule); |
---|
| 618 | this.update(); |
---|
| 619 | this.fireEvent("rulemoved", this, srcRule); |
---|
| 620 | }, |
---|
| 621 | |
---|
| 622 | /** private: method[getRuleTitle] |
---|
| 623 | * :returns: ``String`` |
---|
| 624 | * |
---|
| 625 | * Get a rule title given a rule. |
---|
| 626 | */ |
---|
| 627 | getRuleTitle: function(rule) { |
---|
| 628 | var title = rule.title || rule.name || ""; |
---|
| 629 | if (!title && this.untitledPrefix) { |
---|
| 630 | title = this.untitledPrefix + (this.rules.indexOf(rule) + 1); |
---|
| 631 | } |
---|
| 632 | return title; |
---|
| 633 | }, |
---|
| 634 | |
---|
| 635 | /** private: method[beforeDestroy] |
---|
| 636 | * Override. |
---|
| 637 | */ |
---|
| 638 | beforeDestroy: function() { |
---|
| 639 | if (this.layer) { |
---|
| 640 | if (this.layer.events) { |
---|
| 641 | this.layer.events.un({ |
---|
| 642 | featuresadded: this.onFeaturesAdded, |
---|
| 643 | scope: this |
---|
| 644 | }); |
---|
| 645 | } |
---|
| 646 | if (this.layer.map && this.layer.map.events) { |
---|
| 647 | this.layer.map.events.un({ |
---|
| 648 | "zoomend": this.onMapZoom, |
---|
| 649 | scope: this |
---|
| 650 | }); |
---|
| 651 | } |
---|
| 652 | } |
---|
| 653 | delete this.layer; |
---|
| 654 | delete this.rules; |
---|
| 655 | GeoExt.VectorLegend.superclass.beforeDestroy.apply(this, arguments); |
---|
| 656 | } |
---|
| 657 | |
---|
| 658 | }); |
---|
| 659 | |
---|
| 660 | /** private: method[supports] |
---|
| 661 | * Private override |
---|
| 662 | */ |
---|
| 663 | GeoExt.VectorLegend.supports = function(layerRecord) { |
---|
| 664 | return layerRecord.getLayer() instanceof OpenLayers.Layer.Vector; |
---|
| 665 | }; |
---|
| 666 | |
---|
| 667 | /** api: legendtype = gx_vectorlegend */ |
---|
| 668 | GeoExt.LayerLegend.types["gx_vectorlegend"] = GeoExt.VectorLegend; |
---|
| 669 | |
---|
| 670 | /** api: xtype = gx_vectorlegend */ |
---|
| 671 | Ext.reg("gx_vectorlegend", GeoExt.VectorLegend); |
---|