[Commits] r1999 - in core/trunk/geoext: examples lib lib/GeoExt/widgets tests tests/lib/GeoExt/widgets
commits at geoext.org
commits at geoext.org
Wed Mar 17 17:02:00 CET 2010
Author: tschaub
Date: 2010-03-17 17:02:00 +0100 (Wed, 17 Mar 2010)
New Revision: 1999
Added:
core/trunk/geoext/examples/vector-legend.html
core/trunk/geoext/examples/vector-legend.js
core/trunk/geoext/lib/GeoExt/widgets/VectorLegend.js
core/trunk/geoext/tests/lib/GeoExt/widgets/VectorLegend.html
Modified:
core/trunk/geoext/lib/GeoExt.js
core/trunk/geoext/lib/GeoExt/widgets/LayerLegend.js
core/trunk/geoext/tests/lib/GeoExt/widgets/LayerLegend.html
core/trunk/geoext/tests/lib/GeoExt/widgets/LegendPanel.html
core/trunk/geoext/tests/list-tests.html
Log:
Adding a legend component for vector layers. This can be constructed with a vector layer or a list of rules and a symbolizer type. To use a legend panel without entries for your vector layers, set layer.displayInLayerSwitcher to false. r=elemoine closes #174
Added: core/trunk/geoext/examples/vector-legend.html
===================================================================
--- core/trunk/geoext/examples/vector-legend.html (rev 0)
+++ core/trunk/geoext/examples/vector-legend.html 2010-03-17 16:02:00 UTC (rev 1999)
@@ -0,0 +1,42 @@
+<html>
+ <head>
+ <title>GeoExt Vector Legend</title>
+
+ <script type="text/javascript" src="http://extjs.cachefly.net/ext-2.2.1/adapter/ext/ext-base.js"></script>
+ <script type="text/javascript" src="http://extjs.cachefly.net/ext-2.2.1/ext-all.js"></script>
+ <link rel="stylesheet" type="text/css" href="http://extjs.cachefly.net/ext-2.2.1/resources/css/ext-all.css" />
+ <link rel="stylesheet" type="text/css" href="http://extjs.cachefly.net/ext-2.2.1/examples/shared/examples.css" />
+ <script src="http://openlayers.org/api/2.8/OpenLayers.js"></script>
+ <script type="text/javascript" src="../lib/GeoExt.js"></script>
+
+ <script type="text/javascript" src="vector-legend.js"></script>
+ <style>
+ #wrapper {
+ position: relative;
+ }
+ #mappanel {
+ position: absolute;
+ top: 0px;
+ left: 0px;
+ width: 512px;
+ height: 256px;
+ }
+ #legend {
+ position: absolute;
+ top: 0px;
+ left: 550px;
+ height: 256px;
+ width: 150px;
+ }
+ </style>
+ </head>
+ <body>
+ <h1>GeoExt.LegendPanel with Vector Layers</h1>
+ <p>This example shows the how to create a legend for vector layers. Zoom out to see how the legend is updated with changes in scale.<p>
+ <p>The js is not minified so it is readable. See <a href="vector-legend.js">vector-legend.js</a>.</p>
+ <div id="wrapper">
+ <div id="mappanel"></div>
+ <div id="legend"></div>
+ </div>
+ </body>
+</html>
Added: core/trunk/geoext/examples/vector-legend.js
===================================================================
--- core/trunk/geoext/examples/vector-legend.js (rev 0)
+++ core/trunk/geoext/examples/vector-legend.js 2010-03-17 16:02:00 UTC (rev 1999)
@@ -0,0 +1,99 @@
+var mapPanel, legendPanel;
+
+Ext.onReady(function() {
+
+ var rules = [
+ new OpenLayers.Rule({
+ title: "> 2000m",
+ maxScaleDenominator: 3000000,
+ filter: new OpenLayers.Filter.Comparison({
+ type: OpenLayers.Filter.Comparison.GREATER_THAN,
+ property: "elevation",
+ value: 2000
+ }),
+ symbolizer: {
+ graphicName: "star",
+ pointRadius: 8,
+ fillColor: "#99ccff",
+ strokeColor: "#666666",
+ strokeWidth: 1
+ }
+ }),
+ new OpenLayers.Rule({
+ title: "1500 - 2000m",
+ maxScaleDenominator: 3000000,
+ filter: new OpenLayers.Filter.Comparison({
+ type: OpenLayers.Filter.Comparison.BETWEEN,
+ property: "elevation",
+ upperBoundary: 2000,
+ lowerBoundary: 1500
+ }),
+ symbolizer: {
+ graphicName: "star",
+ pointRadius: 6,
+ fillColor: "#6699cc",
+ strokeColor: "#666666",
+ strokeWidth: 1
+ }
+ }),
+ new OpenLayers.Rule({
+ title: "< 1500m",
+ maxScaleDenominator: 3000000,
+ filter: new OpenLayers.Filter.Comparison({
+ type: OpenLayers.Filter.Comparison.LESS_THAN,
+ property: "elevation",
+ value: 1500
+ }),
+ symbolizer: {
+ graphicName: "star",
+ pointRadius: 4,
+ fillColor: "#0033cc",
+ strokeColor: "#666666",
+ strokeWidth: 1
+ }
+ }),
+ new OpenLayers.Rule({
+ title: "All",
+ minScaleDenominator: 3000000,
+ symbolizer: {
+ graphicName: "star",
+ pointRadius: 5,
+ fillColor: "#99ccff",
+ strokeColor: "#666666",
+ strokeWidth: 1
+ }
+ })
+ ];
+
+ var imagery = new OpenLayers.Layer.WMS(
+ "Imagery",
+ "http://maps.opengeo.org/geowebcache/service/wms",
+ {layers: "bluemarble"},
+ {displayInLayerSwitcher: false}
+ );
+
+ var summits = new OpenLayers.Layer.Vector("Summits", {
+ strategies: [new OpenLayers.Strategy.Fixed()],
+ protocol: new OpenLayers.Protocol.HTTP({
+ url: "data/summits.json",
+ format: new OpenLayers.Format.GeoJSON()
+ }),
+ styleMap: new OpenLayers.StyleMap(new OpenLayers.Style({}, {rules: rules}))
+ });
+
+ mapPanel = new GeoExt.MapPanel({
+ renderTo: "mappanel",
+ border: false,
+ layers: [imagery, summits],
+ center: [6.3, 45.6],
+ height: 256, // IE6 wants this
+ zoom: 8
+ });
+
+ legendPanel = new GeoExt.LegendPanel({
+ map: mapPanel.map,
+ renderTo: "legend",
+ border: false
+ });
+
+});
Modified: core/trunk/geoext/lib/GeoExt/widgets/LayerLegend.js
===================================================================
--- core/trunk/geoext/lib/GeoExt/widgets/LayerLegend.js 2010-03-17 15:13:09 UTC (rev 1998)
+++ core/trunk/geoext/lib/GeoExt/widgets/LayerLegend.js 2010-03-17 16:02:00 UTC (rev 1999)
@@ -32,6 +32,13 @@
* on the LayerStore record using the hideTitle property.
*/
showTitle: true,
+
+ /** api: config[legendTitle]
+ * ``String``
+ * Optional title to be displayed instead of the layer title. If this is
+ * set, the value of ``showTitle`` will be ignored (assumed to be true).
+ */
+ legendTitle: null,
/** api: config[labelCls]
* ``String``
@@ -71,9 +78,13 @@
* name.
*/
getLayerTitle: function(record) {
- var title = "";
- if (this.showTitle && !record.get("hideTitle")) {
- title = record.get("title") || record.get("name") || record.get("layer").name || "";
+ var title = this.legendTitle || "";
+ if (this.showTitle && !title) {
+ if (record && !record.get("hideTitle")) {
+ title = record.get("title") ||
+ record.get("name") ||
+ record.get("layer").name || "";
+ }
}
return title;
}
Added: core/trunk/geoext/lib/GeoExt/widgets/VectorLegend.js
===================================================================
--- core/trunk/geoext/lib/GeoExt/widgets/VectorLegend.js (rev 0)
+++ core/trunk/geoext/lib/GeoExt/widgets/VectorLegend.js 2010-03-17 16:02:00 UTC (rev 1999)
@@ -0,0 +1,606 @@
+/**
+ * Copyright (c) 2008-2010 The Open Source Geospatial Foundation
+ *
+ * Published under the BSD license.
+ * See http://svn.geoext.org/core/trunk/geoext/license.txt for the full text
+ * of the license.
+ */
+
+/**
+ * @requires GeoExt/widgets/LayerLegend.js
+ */
+
+/** api: (define)
+ * module = GeoExt
+ * class = VectorLegend
+ * base_link = `Ext.Panel <http://extjs.com/deploy/dev/docs/?class=Ext.Panel>`_
+ */
+
+Ext.namespace('GeoExt');
+
+/** api: constructor
+ * .. class:: VectorLegend(config)
+ *
+ * Create a vector legend.
+ */
+GeoExt.VectorLegend = Ext.extend(GeoExt.LayerLegend, {
+
+ /** api: config[layerRecord]
+ * :class:`GeoExt.data.LayerRecord`
+ * The record containing a vector layer that this legend will be based on.
+ * One of ``layerRecord``, ``layer``, or ``rules`` must be specified in
+ * the config.
+ */
+ layerRecord: null,
+
+ /** api: config[layer]
+ * ``OpenLayers.Layer.Vector``
+ * The layer that this legend will be based on. One of ``layer``,
+ * ``rules``, or ``layerRecord`` must be specified in the config.
+ */
+ layer: null,
+
+ /** api: config[rules]
+ * ``Array(OpenLayers.Rule)``
+ * List of rules. One of ``rules``, ``layer``, or ``layerRecord`` must be
+ * specified in the config. The ``symbolType`` property must also be
+ * provided if only ``rules`` are given in the config.
+ */
+ rules: null,
+
+ /** api: config[symbolType]
+ * ``String``
+ * The symbol type for legend swatches. Must be one of ``"Point"``,
+ * ``"Line"``, or ``"Polygon"``. If not provided, the ``layer`` or
+ * ``layerRecord`` config property must be specified, and the geometry type
+ * of the first feature found on the layer will be used.
+ */
+ symbolType: null,
+
+ /** api: config[untitledPrefix]
+ * ``String``
+ * The prefix to use as a title for rules with no title or
+ * name. Default is ``"Untitled "``. Prefix will be appended with a
+ * number.
+ */
+ untitledPrefix: "Untitled ",
+
+ /** api: config[clickableSymbol]
+ * ``Boolean``
+ * Set cursor style to "pointer" for symbolizers. Register for
+ * the ``symbolclick`` event to handle clicks. Note that click events
+ * are fired regardless of this value. If ``false``, no cursor style will
+ * be set. Default is ``false``.
+ */
+ clickableSymbol: false,
+
+ /** api: config[clickableTitle]
+ * ``Boolean``
+ * Set cursor style to "pointer" for rule titles. Register for
+ * the ``titleclick`` event to handle clicks. Note that click events
+ * are fired regardless of this value. If ``false``, no cursor style will
+ * be set. Default is ``false``.
+ */
+ clickableTitle: false,
+
+ /** api: config[selectOnClick]
+ * ``Boolean``
+ * Set to true if a rule should be selected by clicking on the
+ * symbol or title. Selection will trigger the ruleselected event, and
+ * a click on a selected rule will unselect it and trigger the
+ * ``ruleunselected`` event. Default is ``false``.
+ */
+ selectOnClick: false,
+
+ /** api: config[enableDD]
+ * ``Boolean``
+ * Allow drag and drop of rules. Default is ``false``.
+ */
+ enableDD: false,
+
+ /** api: config[bodyBorder]
+ * ``Boolean``
+ * Show a border around the legend panel. Default is ``false``.
+ */
+ bodyBorder: false,
+
+ /** private: property[feature]
+ * ``OpenLayers.Feature.Vector``
+ * Cached feature for rendering.
+ */
+ feature: null,
+
+ /** private: property[selectedRule]
+ * ``OpenLayers.Rule``
+ * The rule that is currently selected.
+ */
+ selectedRule: null,
+
+ /** private: property[currentScaleDenominator]
+ * ``Number``
+ * The current scale denominator of any map associated with this
+ * legend. Use :meth`setCurrentScaleDenominator` to change this. If not
+ * set an entry for each rule will be rendered. If set, only rules that
+ * apply for the given scale will be rendered.
+ */
+ currentScaleDenominator: null,
+
+ /** private: property[untitledCount]
+ * ``Number``
+ * Last number used for untitled rule.
+ */
+ untitledCount: 0,
+
+ /** private: method[initComponent]
+ * Initializes the Vector legend.
+ */
+ initComponent: function() {
+ GeoExt.VectorLegend.superclass.initComponent.call(this);
+ if (this.layerRecord) {
+ this.layer = this.layerRecord.get("layer");
+ if (this.layer.map) {
+ this.currentScaleDenominator = this.layer.map.getScale();
+ this.layer.map.events.on({
+ "zoomend": this.onMapZoom,
+ scope: this
+ });
+ }
+ }
+
+ // determine symbol type
+ if (!this.symbolType) {
+ if (this.feature) {
+ this.symbolType = this.symbolTypeFromFeature(this.feature);
+ } else if (this.layer) {
+ if (this.layer.features.length > 0) {
+ var feature = this.layer.features[0].clone();
+ feature.attributes = {};
+ this.feature = feature;
+ this.symbolType = this.symbolTypeFromFeature(this.feature);
+ } else {
+ this.layer.events.on({
+ featuresadded: this.onFeaturesAdded,
+ scope: this
+ });
+ }
+ }
+ }
+
+ // set rules if not provided
+ if (this.layer && this.feature && !this.rules) {
+ this.setRules();
+ }
+
+ this.rulesContainer = new Ext.Container({
+ autoEl: {}
+ });
+
+ this.add(this.rulesContainer);
+
+ this.addEvents(
+ /** api: event[titleclick]
+ * Fires when a rule title is clicked.
+ *
+ * Listener arguments:
+ * * comp - :class:`GeoExt.VectorLegend`` This component.
+ * * rule - ``OpenLayers.Rule`` The rule whose title was clicked.
+ */
+ "titleclick",
+
+ /** api: event[symbolclick]
+ * Fires when a rule symbolizer is clicked.
+ *
+ * Listener arguments:
+ * * comp - :class:`GeoExt.VectorLegend`` This component.
+ * * rule - ``OpenLayers.Rule`` The rule whose symbol was clicked.
+ */
+ "symbolclick",
+
+ /** api: event[ruleclick]
+ * Fires when a rule entry is clicked (fired with symbolizer or
+ * title click).
+ *
+ * Listener arguments:
+ * * comp - :class:`GeoExt.VectorLegend`` This component.
+ * * rule - ``OpenLayers.Rule`` The rule that was clicked.
+ */
+ "ruleclick",
+
+ /** api: event[ruleselected]
+ * Fires when a rule is clicked and ``selectOnClick`` is set to
+ * ``true``.
+ *
+ * Listener arguments:
+ * * comp - :class:`GeoExt.VectorLegend`` This component.
+ * * rule - ``OpenLayers.Rule`` The rule that was selected.
+ */
+ "ruleselected",
+
+ /** api: event[ruleunselected]
+ * Fires when the selected rule is clicked and ``selectOnClick``
+ * is set to ``true``, or when a rule is unselected by selecting a
+ * different one.
+ *
+ * Listener arguments:
+ * * comp - :class:`GeoExt.VectorLegend`` This component.
+ * * rule - ``OpenLayers.Rule`` The rule that was unselected.
+ */
+ "ruleunselected",
+
+ /** api: event[rulemoved]
+ * Fires when a rule is moved.
+ *
+ * Listener arguments:
+ * * comp - :class:`GeoExt.VectorLegend`` This component.
+ * * rule - ``OpenLayers.Rule`` The rule that was moved.
+ */
+ "rulemoved"
+ );
+
+ this.update();
+ },
+
+ /** private: method[onMapZoom]
+ * Listener for map zoomend.
+ */
+ onMapZoom: function() {
+ this.setCurrentScaleDenominator(
+ this.layer.map.getScale()
+ );
+ },
+
+ /** private: method[symbolTypeFromFeature]
+ * :arg feature: ``OpenLayers.Feature.Vector``
+ *
+ * Determine the symbol type given a feature.
+ */
+ symbolTypeFromFeature: function(feature) {
+ var match = feature.geometry.CLASS_NAME.match(/Point|Line|Polygon/);
+ return (match && match[0]) || "Point";
+ },
+
+ /** private: method[onFeaturesAdded]
+ * Set as a one time listener for the ``featuresadded`` event on the layer
+ * if it was provided with no features originally.
+ */
+ onFeaturesAdded: function() {
+ this.layer.events.un({
+ featuresadded: this.onFeaturesAdded,
+ scope: this
+ });
+ var feature = this.layer.features[0].clone();
+ feature.attributes = {};
+ this.feature = feature;
+ this.symbolType = this.symbolTypeFromFeature(this.feature);
+ if (!this.rules) {
+ this.setRules();
+ }
+ this.update();
+ },
+
+ /** private: method[setRules]
+ * Sets the ``rules`` property for this. This is called when the component
+ * is constructed without rules. Rules will be derived from the layer's
+ * style map if it has one.
+ */
+ setRules: function() {
+ var style = this.layer.styleMap && this.layer.styleMap.styles["default"];
+ if (!style) {
+ style = new OpenLayers.Style();
+ }
+ if (style.rules.length === 0) {
+ this.rules = [
+ new OpenLayers.Rule({
+ symbolizer: style.createSymbolizer(this.feature)
+ })
+ ];
+ } else {
+ this.rules = style.rules;
+ }
+ },
+
+ /** api: method[setCurrentScaleDenominator]
+ * :arg scale: ``Number`` The scale denominator.
+ *
+ * Set the current scale denominator. This will hide entries for any
+ * rules that don't apply at the current scale.
+ */
+ setCurrentScaleDenominator: function(scale) {
+ if (scale !== this.currentScaleDenominator) {
+ this.currentScaleDenominator = scale;
+ this.update();
+ }
+ },
+
+ /** private: method[getRuleEntry]
+ * :arg rule: ``OpenLayers.Rule``
+ * :returns: ``Ext.Container``
+ *
+ * Get the item corresponding to the rule.
+ */
+ getRuleEntry: function(rule) {
+ return this.rulesContainer.items.get(this.rules.indexOf(rule));
+ },
+
+ /** private: method[addRuleEntry]
+ * :arg rule: ``OpenLayers.Rule``
+ * :arg noDoLayout: ``Boolean`` Don't call doLayout after adding rule.
+ * Default is ``false``.
+ *
+ * Add a new rule entry in the rules container. This
+ * method does not add the rule to the rules array.
+ */
+ addRuleEntry: function(rule, noDoLayout) {
+ this.rulesContainer.add(this.createRuleEntry(rule));
+ if (!noDoLayout) {
+ this.doLayout();
+ }
+ },
+
+ /** private: method[removeRuleEntry]
+ * :arg rule: ``OpenLayers.Rule``
+ * :arg noDoLayout: ``Boolean`` Don't call doLayout after removing rule.
+ * Default is ``false``.
+ *
+ * Remove a rule entry from the rules container, this
+ * method assumes the rule is in the rules array, and
+ * it does not remove the rule from the rules array.
+ */
+ removeRuleEntry: function(rule, noDoLayout) {
+ var ruleEntry = this.getRuleEntry(rule);
+ if (ruleEntry) {
+ this.rulesContainer.remove(ruleEntry);
+ if (!noDoLayout) {
+ this.doLayout();
+ }
+ }
+ },
+
+ /** private: method[selectRuleEntry]
+ */
+ selectRuleEntry: function(rule) {
+ var newSelection = rule != this.selectedRule;
+ if (this.selectedRule) {
+ this.unselect();
+ }
+ if (newSelection) {
+ var ruleEntry = this.getRuleEntry(rule);
+ ruleEntry.body.addClass("x-grid3-row-selected");
+ this.selectedRule = rule;
+ this.fireEvent("ruleselected", this, rule);
+ }
+ },
+
+ /** private: method[unselect]
+ */
+ unselect: function() {
+ this.rulesContainer.items.each(function(item, i) {
+ if (this.rules[i] == this.selectedRule) {
+ item.body.removeClass("x-grid3-row-selected");
+ this.selectedRule = null;
+ this.fireEvent("ruleunselected", this, this.rules[i]);
+ }
+ }, this);
+ },
+
+ /** private: method[createRuleEntry]
+ */
+ createRuleEntry: function(rule) {
+ var applies = true;
+ if (this.currentScaleDenominator != null) {
+ if (rule.minScaleDenominator) {
+ applies = applies && (this.currentScaleDenominator >= rule.minScaleDenominator);
+ }
+ if (rule.maxScaleDenominator) {
+ applies = applies && (this.currentScaleDenominator < rule.maxScaleDenominator);
+ }
+ }
+ return {
+ xtype: "panel",
+ layout: "column",
+ border: false,
+ hidden: !applies,
+ bodyStyle: this.selectOnClick ? {cursor: "pointer"} : undefined,
+ defaults: {
+ border: false
+ },
+ items: [
+ this.createRuleRenderer(rule),
+ this.createRuleTitle(rule)
+ ],
+ listeners: {
+ render: function(comp){
+ this.selectOnClick && comp.getEl().on({
+ click: function(comp){
+ this.selectRuleEntry(rule);
+ },
+ scope: this
+ });
+ if (this.enableDD == true) {
+ this.addDD(comp);
+ }
+ },
+ scope: this
+ }
+ };
+ },
+
+ /** private: method[createRuleRenderer]
+ * :arg rule: ``OpenLayers.Rule``
+ * :returns: ``GeoExt.FeatureRenderer``
+ *
+ * Create a renderer for the rule.
+ */
+ createRuleRenderer: function(rule) {
+ var symbolizer = rule.symbolizer;
+ if (symbolizer[this.symbolType]) {
+ symbolizer = symbolizer[this.symbolType];
+ }
+ return {
+ xtype: "gx_renderer",
+ symbolType: this.symbolType,
+ symbolizers: [symbolizer],
+ style: this.clickableSymbol ? {cursor: "pointer"} : undefined,
+ listeners: {
+ click: function() {
+ if (this.clickableSymbol) {
+ this.fireEvent("symbolclick", this, rule);
+ this.fireEvent("ruleclick", this, rule);
+ }
+ },
+ scope: this
+ }
+ };
+ },
+
+ /** private: method[createRuleTitle]
+ * :arg rule: ``OpenLayers.Rule``
+ * :returns: ``Ext.Component``
+ *
+ * Create a title component for the rule.
+ */
+ createRuleTitle: function(rule) {
+ return {
+ cls: "x-form-item",
+ style: "padding: 0.2em 0.5em 0;", // TODO: css
+ bodyStyle: Ext.applyIf({background: "transparent"},
+ this.clickableTitle ? {cursor: "pointer"} : undefined),
+ html: this.getRuleTitle(rule),
+ listeners: {
+ render: function(comp) {
+ this.clickableTitle && comp.getEl().on({
+ click: function() {
+ this.fireEvent("titleclick", this, rule);
+ this.fireEvent("ruleclick", this, rule);
+ },
+ scope: this
+ });
+ },
+ scope: this
+ }
+ };
+ },
+
+ /** private: method[addDD]
+ * :arg component: ``Ext.Component``
+ *
+ * Adds drag & drop functionality to a rule entry.
+ */
+ addDD: function(component) {
+ var cursor = component.body.getStyle("cursor");
+ var dd = new Ext.Panel.DD(component);
+ // restore previous curser (if set). because Panel.DD always
+ // sets a move cursor
+ component.body.setStyle("cursor", cursor || "move");
+ var panel = this;
+ var dropZone = new Ext.dd.DropTarget(component.getEl(), {
+ notifyDrop: function(ddSource) {
+ var source = Ext.getCmp(ddSource.getEl().id);
+ var target = Ext.getCmp(this.getEl().id);
+ // sometimes, for whatever reason, Ext forgets who the source
+ // was, so we make sure that we have one before moving on
+ if (source && target && source != target) {
+ var sourceCt = source.ownerCt;
+ var targetCt = target.ownerCt;
+ // only move rules around inside the same container
+ if (sourceCt == targetCt) {
+ panel.moveRule(
+ sourceCt.items.indexOf(source),
+ targetCt.items.indexOf(target)
+ );
+ }
+ }
+ }
+ });
+ },
+
+ /** api: method[update]
+ * Update rule titles and symbolizers.
+ */
+ update: function() {
+ if (this.symbolType && this.rules) {
+ if (this.rulesContainer.items) {
+ var comp;
+ for (var i=this.rulesContainer.items.length-1; i>=0; --i) {
+ comp = this.rulesContainer.getComponent(i);
+ this.rulesContainer.remove(comp, true);
+ }
+ }
+ for (var i=0, ii=this.rules.length; i<ii; ++i) {
+ this.addRuleEntry(this.rules[i], true);
+ }
+ this.doLayout();
+ }
+ },
+
+ /** private: method[updateRuleEntry]
+ * :arg rule: ``OpenLayers.Rule``
+ *
+ * Update the renderer and the title of a rule.
+ */
+ updateRuleEntry: function(rule) {
+ var ruleEntry = this.getRuleEntry(rule);
+ if (ruleEntry) {
+ ruleEntry.removeAll();
+ ruleEntry.add(this.createRuleRenderer(rule));
+ ruleEntry.add(this.createRuleTitle(rule));
+ ruleEntry.doLayout();
+ }
+ },
+
+ /** private: method[moveRule]
+ */
+ moveRule: function(sourcePos, targetPos) {
+ var srcRule = this.rules[sourcePos];
+ this.rules.splice(sourcePos, 1);
+ this.rules.splice(targetPos, 0, srcRule);
+ this.update();
+ this.fireEvent("rulemoved", this, srcRule);
+ },
+
+ /** private: method[getRuleTitle]
+ * :returns: ``String``
+ *
+ * Get a rule title given a rule.
+ */
+ getRuleTitle: function(rule) {
+ return rule.title || rule.name || (this.untitledPrefix + (++this.untitledCount));
+ },
+
+ /** private: method[beforeDestroy]
+ * Override.
+ */
+ beforeDestroy: function() {
+ if (this.layer) {
+ if (this.layer.events) {
+ this.layer.events.un({
+ featuresadded: this.onFeaturesAdded,
+ scope: this
+ });
+ }
+ if (this.layer.map && this.layer.map.events) {
+ this.layer.map.events.un({
+ "zoomend": this.onMapZoom,
+ scope: this
+ });
+ }
+ }
+ delete this.layer;
+ delete this.rules;
+ GeoExt.VectorLegend.superclass.beforeDestroy.apply(this, arguments);
+ }
+
+});
+
+/** private: method[supports]
+ * Private override
+ */
+GeoExt.VectorLegend.supports = function(layerRecord) {
+ return layerRecord.get("layer") instanceof OpenLayers.Layer.Vector;
+};
+
+/** api: legendtype = gx_vectorlegend */
+GeoExt.LayerLegend.types["gx_vectorlegend"] = GeoExt.VectorLegend;
+
+/** api: xtype = gx_vectorlegend */
+Ext.reg("gx_vectorlegend", GeoExt.VectorLegend);
Modified: core/trunk/geoext/lib/GeoExt.js
===================================================================
--- core/trunk/geoext/lib/GeoExt.js 2010-03-17 15:13:09 UTC (rev 1998)
+++ core/trunk/geoext/lib/GeoExt.js 2010-03-17 16:02:00 UTC (rev 1999)
@@ -105,6 +105,7 @@
"GeoExt/widgets/LegendImage.js",
"GeoExt/widgets/UrlLegend.js",
"GeoExt/widgets/WMSLegend.js",
+ "GeoExt/widgets/VectorLegend.js",
"GeoExt/widgets/LegendPanel.js",
"GeoExt/widgets/ZoomSlider.js",
"GeoExt/widgets/grid/FeatureSelectionModel.js",
Modified: core/trunk/geoext/tests/lib/GeoExt/widgets/LayerLegend.html
===================================================================
--- core/trunk/geoext/tests/lib/GeoExt/widgets/LayerLegend.html 2010-03-17 15:13:09 UTC (rev 1998)
+++ core/trunk/geoext/tests/lib/GeoExt/widgets/LayerLegend.html 2010-03-17 16:02:00 UTC (rev 1999)
@@ -36,7 +36,7 @@
}
function test_update(t) {
- t.plan(2);
+ t.plan(3);
var Rec = GeoExt.data.LayerRecord.create([{
name: "hideTitle", type: "boolean"
@@ -66,10 +66,22 @@
t.eq(legend.items.get(0).text, "", "Layer text for record with hideTitle set to true still empty after update.")
legend.destroy();
+ rec = new Rec({
+ layer: new OpenLayers.Layer("foo")
+ });
+ legend = new GeoExt.LayerLegend({
+ layerRecord: rec,
+ legendTitle: "bar",
+ renderTo: "legend"
+ });
+ legend.update();
+ t.eq(legend.items.get(0).text, "bar", "legendTitle can be used to override layer name")
+ legend.destroy();
+
}
function test_getTypes(t) {
- t.plan(4);
+ t.plan(5);
var Rec = GeoExt.data.LayerRecord.create([{
name: "legendURL"
}]);
@@ -88,6 +100,12 @@
layer: new OpenLayers.Layer.WMS()
});
t.eq(GeoExt.LayerLegend.getTypes(rec), ["gx_wmslegend"], "a layer record with wms layer is supported by gx_wmslegend only.");
+
+ rec = new Rec({
+ layer: new OpenLayers.Layer.Vector()
+ });
+ t.eq(GeoExt.LayerLegend.getTypes(rec), ["gx_vectorlegend"], "a layer record with vector layer is supported by gx_vectorlegend only.");
+
}
</script>
Modified: core/trunk/geoext/tests/lib/GeoExt/widgets/LegendPanel.html
===================================================================
--- core/trunk/geoext/tests/lib/GeoExt/widgets/LegendPanel.html 2010-03-17 15:13:09 UTC (rev 1998)
+++ core/trunk/geoext/tests/lib/GeoExt/widgets/LegendPanel.html 2010-03-17 16:02:00 UTC (rev 1999)
@@ -49,12 +49,12 @@
vectorLayer.setVisibility(false);
- t.eq(lp.items.length, 1, "Currently there are no legends for non WMS layers");
+ t.eq(lp.items.length, 2, "legend for vector layer");
var wms = new OpenLayers.Layer.WMS("testArray", '/ows', {layers: ['a', 'b', 'c']});
mapPanel.map.addLayer(wms);
- t.eq(lp.items.length, 2, "The legend panel can deal with WMS layers which have a LAYERS params which is an array");
+ t.eq(lp.items.length, 3, "The legend panel can deal with WMS layers which have a LAYERS params which is an array");
lp.destroy();
mapPanel.destroy();
Added: core/trunk/geoext/tests/lib/GeoExt/widgets/VectorLegend.html
===================================================================
--- core/trunk/geoext/tests/lib/GeoExt/widgets/VectorLegend.html (rev 0)
+++ core/trunk/geoext/tests/lib/GeoExt/widgets/VectorLegend.html 2010-03-17 16:02:00 UTC (rev 1999)
@@ -0,0 +1,89 @@
+<html><head>
+ <script src="../../../../../openlayers/lib/OpenLayers.js"></script>
+ <script src="../../../../../ext/adapter/ext/ext-base.js"></script>
+ <script src="../../../../../ext/ext-all.js"></script>
+ <script src="../../../../lib/GeoExt.js"></script>
+
+ <script>
+
+ function test_constructor(t) {
+ t.plan(5);
+
+ var legend;
+
+ // no config (won't render)
+ legend = new GeoExt.VectorLegend();
+ t.ok(legend instanceof GeoExt.VectorLegend, "instance of VectorLegend");
+ t.ok(legend instanceof GeoExt.LayerLegend, "instance of LayerLegend");
+ legend.destroy();
+
+ // rules & symbolType
+ legend = new GeoExt.VectorLegend({
+ legendTitle: "my title",
+ renderTo: "legendpanel",
+ rules: [
+ new OpenLayers.Rule({title: "first rule"}),
+ new OpenLayers.Rule({title: "second rule"})
+ ],
+ symbolType: "Point"
+ });
+
+ // check title
+ var titleCmp = legend.getComponent(0);
+ t.eq(titleCmp.getEl().dom.innerHTML, "my title", "correct legend title");
+
+ // check rule components
+ t.eq(legend.rulesContainer.items.length, 2, "two items in the rules container");
+ var ruleCmp = legend.rulesContainer.getComponent(0);
+ var ruleTitleCmp = ruleCmp.getComponent(1);
+ // this should eventually become a container instead of a panel
+ t.ok(ruleTitleCmp.getEl().dom.innerHTML.indexOf("first rule") > -1, "correct title for first rule");
+
+ legend.destroy();
+ }
+
+ function test_setCurrentScaleDenominator(t) {
+ t.plan(12);
+
+ var legend = new GeoExt.VectorLegend({
+ legendTitle: "my title",
+ renderTo: "legendpanel",
+ rules: [
+ new OpenLayers.Rule({title: "first rule", maxScaleDenominator: 100}),
+ new OpenLayers.Rule({title: "second rule", minScaleDenominator: 100})
+ ],
+ symbolType: "Point"
+ });
+
+ // all rules shown if no scale denominator is set
+ t.eq(legend.rulesContainer.items.length, 2, "two items in the rules container");
+ t.eq(legend.rulesContainer.getComponent(0).hidden, false, "first rule shown");
+ t.eq(legend.rulesContainer.getComponent(1).hidden, false, "second rule shown");
+
+ // show first rule at 1:50
+ legend.setCurrentScaleDenominator(50)
+ t.eq(legend.rulesContainer.items.length, 2, "two items in the rules container at 1:50");
+ t.eq(legend.rulesContainer.getComponent(0).hidden, false, "first rule shown at 1:50");
+ t.eq(legend.rulesContainer.getComponent(1).hidden, true, "second rule hidden at 1:50");
+
+ // show second rule at 1:150
+ legend.setCurrentScaleDenominator(150)
+ t.eq(legend.rulesContainer.items.length, 2, "two items in the rules container at 1:150");
+ t.eq(legend.rulesContainer.getComponent(0).hidden, true, "first rule hidden at 1:150");
+ t.eq(legend.rulesContainer.getComponent(1).hidden, false, "second rule shown at 1:150");
+
+ // show second rule at 1:100 (min is inclusive)
+ legend.setCurrentScaleDenominator(100)
+ t.eq(legend.rulesContainer.items.length, 2, "two items in the rules container at 1:100");
+ t.eq(legend.rulesContainer.getComponent(0).hidden, true, "first rule hidden at 1:100");
+ t.eq(legend.rulesContainer.getComponent(1).hidden, false, "second rule shown at 1:100");
+
+ legend.destroy();
+
+ }
+
+
+ </script>
+</head><body>
+ <div id="legendpanel"></div>
+</body></html>
Modified: core/trunk/geoext/tests/list-tests.html
===================================================================
--- core/trunk/geoext/tests/list-tests.html 2010-03-17 15:13:09 UTC (rev 1998)
+++ core/trunk/geoext/tests/list-tests.html 2010-03-17 16:02:00 UTC (rev 1999)
@@ -39,6 +39,7 @@
<li>lib/GeoExt/widgets/LegendPanel.html</li>
<li>lib/GeoExt/widgets/LayerLegend.html</li>
<li>lib/GeoExt/widgets/UrlLegend.html</li>
+ <li>lib/GeoExt/widgets/VectorLegend.html</li>
<li>lib/GeoExt/widgets/WMSLegend.html</li>
<li>lib/GeoExt/widgets/ZoomSlider.html</li>
<li>lib/GeoExt/widgets/grid/FeatureSelectionModel.html</li>
More information about the Commits
mailing list