Bienvenue sur PostGIS.fr

Bienvenue sur PostGIS.fr , le site de la communauté des utilisateurs francophones de PostGIS.

PostGIS ajoute le support d'objets géographique à la base de données PostgreSQL. En effet, PostGIS "spatialise" le serverur PostgreSQL, ce qui permet de l'utiliser comme une base de données SIG.

Maintenu à jour, en fonction de nos disponibilités et des diverses sorties des outils que nous testons, nous vous proposons l'ensemble de nos travaux publiés en langue française.

source: trunk/workshop-routing-foss4g/web/GeoExt/lib/GeoExt/widgets/VectorLegend.js @ 76

Revision 76, 22.2 KB checked in by djay, 12 years ago (diff)

Ajout du répertoire web

  • Property svn:executable set to *
Line 
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
23Ext.namespace('GeoExt');
24
25/** api: constructor
26 *  .. class:: VectorLegend(config)
27 *
28 *      Create a vector legend.
29 */
30GeoExt.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 */
663GeoExt.VectorLegend.supports = function(layerRecord) {
664    return layerRecord.getLayer() instanceof OpenLayers.Layer.Vector;
665};
666
667/** api: legendtype = gx_vectorlegend */
668GeoExt.LayerLegend.types["gx_vectorlegend"] = GeoExt.VectorLegend;
669
670/** api: xtype = gx_vectorlegend */
671Ext.reg("gx_vectorlegend", GeoExt.VectorLegend); 
Note: See TracBrowser for help on using the repository browser.