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 <[email protected]> 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 <[email protected]> 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
>>>> [email protected]
>>>> 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.
>
>
_______________________________________________
Users mailing list
[email protected]
http://www.geoext.org/cgi-bin/mailman/listinfo/users

Reply via email to