[Users] TreePanel with Vector Legend
Adam Ratcliffe
adam at prema.co.nz
Mon Aug 16 01:44:43 CEST 2010
Hi Andreas,
I had sometime over the weekend to start looking into how to implement
this. Below is my initial attempt, which while working, I'm not
completely happy with. Maybe you or somebody on the else on the list
can suggest some improvements?
Some of the issues that I had were:
- My class duplicates code from GeoExt.VectorLegend
- I needed to override GeoExt.FeatureRenderer.onRender() so that the
wrapper element that's created for the legend swatch is an inline
element rather than a block-level element. It would be helpful if
GeoExt.FeatureRenderer allowed the element type to be specified via
the 'autoEl' config option like other ExtJS components.
- I had issues with vertical alignment of the legend swatch relative
to the node checkbox and label text. I was able to align these
elements satisfactorily under FF and Safari using the styles below - I
haven't tested in IE yet.
Styles
----------
.x-tree-node-legend {
height: 18px;
}
.x-tree-node-legend input {
margin-left: 2px !important;
vertical-align: top !important;
}
.x-tree-node-legend .x-tree-node-anchor span {
vertical-align: top !important;
}
Script
---------
GeoExt.tree.VectorLayerNodeUI = Ext.extend(GeoExt.tree.LayerNodeUI, {
constructor: function(config) {
GeoExt.tree.VectorLayerNodeUI.superclass.constructor.apply(this,
arguments);
if (!this.symbolType) {
if (this.feature) {
this.symbolType = this.symbolTypeFromFeature(this.feature);
} else if (this.node.layer) {
if (this.node.layer.geometryType) {
this.symbolType =
this.symbolTypeFromGeometry(this.node.layer.geometryType);
} else if (this.node.layer.features.length > 0) {
var feature = this.node.layer.features[0].clone();
feature.attributes = {};
this.feature = feature;
this.symbolType = this.symbolTypeFromFeature(this.feature);
} else {
this.node.layer.events.on({
featuresadded: this.onFeaturesAdded,
scope: this
});
}
}
}
this.setRules();
},
symbolTypeFromGeometry: function(geometry) {
var symbolType = geometry.prototype.CLASS_NAME.split('.').pop();
return (symbolType == 'LineString') ? 'Line' : symbolType;
},
symbolTypeFromFeature: function(feature) {
var match = feature.geometry.CLASS_NAME.match(/Point|Line|Polygon/);
return (match && match[0]) || "Point";
},
onFeaturesAdded: function() {
this.node.layer.events.un({
featuresadded: this.onFeaturesAdded,
scope: this
});
var feature = this.node.layer.features[0].clone();
feature.attributes = {};
this.feature = feature;
this.symbolType = this.symbolTypeFromFeature(this.feature);
if (!this.rules) {
this.setRules();
}
this.update();
},
update: function() {
if (this.symbolType && this.rules) {
this.createRuleRenderer(this.rules[0],
this.legendWrap).render(this.elNode, 2);
}
},
setRules: function() {
var style = this.node.layer.styleMap &&
this.node.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;
}
},
createRuleRenderer: function(rule) {
var symbolizer = rule.symbolizer;
if (symbolizer[this.symbolType]) {
symbolizer = symbolizer[this.symbolType];
}
return new GeoExt.FeatureRenderer({
resolution: 1,
width: 18,
height: 18,
symbolType: this.symbolType,
symbolizers: [symbolizer],
// override onRender() so that the vector element can
// be wrapped with an inline element in place of a block element
onRender: function(ct, position) {
if(!this.el) {
this.el = document.createElement('span');
this.el.className = 'legend-wrap';
this.el.id = this.getId();
}
if(!this.renderer || !this.renderer.supported()) {
this.assignRenderer();
}
this.renderer.map = {
getResolution: (function() {
return this.resolution;
}).createDelegate(this)
};
this.drawFeature();
GeoExt.FeatureRenderer.superclass.onRender.apply(this,
arguments);
}
});
},
renderElements : function(n, a, targetNode, bulkRender){
// add some indent caching, this helps performance when
rendering a large tree
this.indentMarkup = n.parentNode ?
n.parentNode.ui.getChildIndent() : '';
var cb = Ext.isBoolean(a.checked),
nel,
href = a.href ? a.href : Ext.isGecko ? "" : "#",
buf = ['<li class="x-tree-node"><div
ext:tree-node-id="',n.id,'" class="x-tree-node-el x-tree-node-leaf
x-tree-node-legend x-unselectable ', a.cls,'" unselectable="on">',
'<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
'<img src="', this.emptyIcon, '" class="x-tree-ec-icon
x-tree-elbow" />',
cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
(a.checked ? 'checked="checked" />' : '/>')) : '',
'<a hidefocus="on" class="x-tree-node-anchor"
href="',href,'" tabIndex="1" ',
a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "", '><span
unselectable="on">',n.text,"</span></a></div>",
'<ul class="x-tree-node-ct" style="display:none;"></ul>',
"</li>"].join('');
if(bulkRender !== true && n.nextSibling && (nel =
n.nextSibling.ui.getEl())){
this.wrap = Ext.DomHelper.insertHtml("beforeBegin", nel, buf);
}else{
this.wrap = Ext.DomHelper.insertHtml("beforeEnd", targetNode, buf);
}
this.elNode = this.wrap.childNodes[0];
this.ctNode = this.wrap.childNodes[1];
var cs = this.elNode.childNodes;
this.indentNode = cs[0];
this.ecNode = cs[1];
var index = 2;
if(cb){
this.checkbox = cs[2];
// fix for IE6
this.checkbox.defaultChecked = this.checkbox.checked;
index++;
}
this.anchor = cs[index];
this.textNode = cs[index].firstChild;
if(this.symbolType) {
this.createRuleRenderer(this.rules[0]).render(this.elNode, 2);
}
}
});
Cheers
Adam
Cheers
Adam
On Mon, Aug 2, 2010 at 7:44 PM, Andreas Hocevar <ahocevar at opengeo.org> wrote:
> Oops, sorry. I had missed the "TreePanel" part of your original mail (thought you wanted a VectorLegend in your LegendPanel). At this point, you cannot render a legend with a tree node. There are several tickets with patches already, which may help you:
>
> http://trac.geoext.org/ticket/185
> http://trac.geoext.org/ticket/139
>
> Regards,
> Andreas.
>
> On Aug 2, 2010, at 09:27 , Adam Ratcliffe wrote:
>
>> That's great.
>>
>> Just one question, how do I configure my TreePanel to create the node
>> with a vector legend instead of an icon, my current tree configuration
>> looks like this:
>>
>> var config = {
>> autoScroll: true,
>> animate: true,
>> border: false,
>> region: 'center',
>> stateful: true,
>> root: new GeoExt.tree.LayerContainer({
>> text: 'Layers',
>> loader: new GeoExt.tree.LayerLoader({
>> store: this.layerStore,
>> createNode: function(attr) {
>> var layer = attr.layer;
>> attr.iconCls = layer.gsGeometryType ? 'icon_'
>> + layer.gsGeometryType.toLowerCase() : 'icon_point';
>> return
>> GeoExt.tree.LayerLoader.prototype.createNode.call(this, attr);
>> }
>> }),
>> layerStore: this.layerStore,
>> leaf: false,
>> expanded: true
>> })
>> }
>>
>> Cheers
>> Adam
>>
>> On Mon, Aug 2, 2010 at 6:13 PM, Andreas Hocevar <ahocevar at opengeo.org> wrote:
>>> Hi,
>>>
>>> On Aug 2, 2010, at 05:41 , Adam Ratcliffe wrote:
>>>
>>>> I'd like to dynamically render symbols based upon the layer geometry
>>>> type and styles in a TreePanel similar to the vector legend example
>>>> here: http://dev.geoext.org/trunk/geoext/examples/vector-legend.html
>>>>
>>>> Is this possible?
>>>
>>> Yes! Just configure your vector layer with a StyleMap. The VectorLegend will be built from the style and rules of the "default" render intent.
>>>
>>> Regards,
>>> Andreas.
>>>
>>>>
>>>> Cheers
>>>> Adam
>>>> _______________________________________________
>>>> Users mailing list
>>>> Users at geoext.org
>>>> http://www.geoext.org/cgi-bin/mailman/listinfo/users
>>>
>>>
>>>
>>> --
>>> Andreas Hocevar
>>> OpenGeo - http://opengeo.org/
>>> Expert service straight from the developers.
>>>
>>>
>
> --
> Andreas Hocevar
> OpenGeo - http://opengeo.org/
> Expert service straight from the developers.
>
>
More information about the Users
mailing list