[GIS] Cluster strategy, problem with labels on uncluster features – undefined

clusteringopenlayers-2

I have vector layer – WFS from GeoServer (Postgis). In the Postgis table there are some attributes e.g.: the_geom (of course), adr_adm, … So I would like display label: adr_adm on features when they are unclustered.
I'm looking for replay in:

Cluster Strategy different Labeling at Different Level

http://www.gistutor.com/openlayers/12-intermediate-openlayers-tutorials/40-styling-and-labeling-vector-layers-in-openlayers.html

http://openflights.org/blog/2009/10/21/customized-openlayers-cluster-strategies/
and many others

I wrote something like that but it still doesn't work. Label for unclustered features still undefined. When I remove cluster strategy features have properly labels.

(I can't get an attribute from an array of features clustered)

Please help me to improve my code.

Thanks for any reply.
I greet.

My code:

    var map;
    var refresh = new OpenLayers.Strategy.Refresh({force: true, active: true});
    var extent = new OpenLayers.Bounds(
                2568598.39063282, 7000794.41264775,
                2586376.89361486, 7012360.91662176);
     OpenLayers.IMAGE_RELOAD_ATTEMPTS = 5;
    var colors = {
low: "#93b772", 
middle: "#f1d046",
high: "#fd9c73", 
s_low: "#465736", 
s_middle: "#9b862d", 
s_high: "#ac6a4e"
    };
    var singleRule = new OpenLayers.Rule({ 
filter: new OpenLayers.Filter.Comparison({
type: OpenLayers.Filter.Comparison.EQUAL_TO,
property: "count",
value: 1
    }),         
symbolizer: {
    fillColor: colors.low,
    fillOpacity: 0.9, 
    strokeColor: colors.s_low,
    strokeOpacity: 0.2,
    strokeWidth: 9,
    pointRadius: 8,
    label: "${text}",
    context:{
        text: function(feature){ return feature.attributes.adr_adm; }
            }, 
    labelAlign: "cc",
    labelXOffset: 4,
    labelOutlineWidth: 0.5,
    fontColor: "#00376d",
    fontOpacity: 1,
    fontSize: "10px"
}
    });
    var lowRule = new OpenLayers.Rule({
filter: new OpenLayers.Filter.Comparison({
    type: OpenLayers.Filter.Comparison.BETWEEN,
    property: "count",
    lowerBoundary: 2,
    upperBoundary: 5
}),
symbolizer: {
    fillColor: colors.low,
    fillOpacity: 0.9, 
    strokeColor: colors.s_low,
    strokeOpacity: 0.2,
    strokeWidth: 11,
    pointRadius: 10,
    label: "${count}",
    labelOutlineWidth: 0.5,
    fontColor: "#00376d",
    fontOpacity: 1,
    fontSize: "10px"
}
    });
    var middleRule = new OpenLayers.Rule({
filter: new OpenLayers.Filter.Comparison({
    type: OpenLayers.Filter.Comparison.BETWEEN,
    property: "count",
    lowerBoundary: 5,
    upperBoundary: 15
}),
symbolizer: {
    fillColor: colors.middle,
    fillOpacity: 0.9, 
    strokeColor: colors.s_middle,
    strokeOpacity: 0.2,
    strokeWidth: 13,
    pointRadius: 12,
    label: "${count}",
    labelOutlineWidth: 0.5,
    fontColor: "#00376d",
    fontOpacity: 1,
    fontSize: "10px"
}
    });
    var highRule = new OpenLayers.Rule({
filter: new OpenLayers.Filter.Comparison({
    type: OpenLayers.Filter.Comparison.GREATER_THAN,
    property: "count",
    value: 15
}),
symbolizer: {
    fillColor: colors.high,
    fillOpacity: 0.9, 
    strokeColor: colors.s_high,
    strokeOpacity: 0.2,
    strokeWidth: 15,
    pointRadius: 14,
    label: "${count}",
    labelOutlineWidth: 0.5,
    fontColor: "#00376d",
    fontOpacity: 1,
    fontSize: "10px"
}
    });
    // Create a Style that uses the three previous rules
    var style = new OpenLayers.Style(null, {
rules: [singleRule, lowRule, middleRule, highRule]
    });

    function init() {

map = new OpenLayers.Map({
    div: "map",
    layers: [
        new OpenLayers.Layer.OSM("OpenStreetMapa")
        ],
    controls: [
        new OpenLayers.Control.Navigation(),
        new OpenLayers.Control.PanZoomBar(),
        new OpenLayers.Control.OverviewMap(),
        new OpenLayers.Control.LayerSwitcher({ascending: false}),
        new OpenLayers.Control.KeyboardDefaults(),
        new OpenLayers.Control.ScaleLine(),
        new OpenLayers.Control.Attribution()
      ],
    projection: "EPSG:3857",
    restrictedExtent: extent,
    }
);

var wc_layer = new OpenLayers.Layer.Vector("WC parametry", {
    strategies: [ new OpenLayers.Strategy.Fixed(),
                  new OpenLayers.Strategy.Cluster({distance: 40}), 
                  refresh],
                protocol: new OpenLayers.Protocol.WFS({
                url: "http://localhost/wfs_ant",  
                featureType: "v_wezly_param",   
                featureNS: "http://mapy.telemetria/"  
                })
                ,styleMap: new OpenLayers.StyleMap(style)
                ,attribution: '   © BB'
                ,extractAttributes: true
});
map.addLayer(wc_layer);

setInterval(function () { refresh.refresh(); },20000);

if(!map.getCenter()){
        map.zoomToExtent(extent);  
    }
         }

Best Answer

Clustered features do not have the same attributes as unclustered features. In your singleRule the attributes are in:

label: "${text}",
context:{
    text: function(feature) {
        return feature.cluster[0].attributes.adr_adm;
    }
}, 

Alternatively, you could adapt your context to take care of this:

label: "${text}",
context:{
    text: function(feature) {
        if(feature.cluster && feature.cluster.length == 1)
            return feature.cluster[0].attributes.adr_adm;
        else if(!feature.cluster)
            return feature.attributes.adr_adm;
        return feature.attributes.count;
    }
}, 

Note that you can also set a threshold in your strategy to not cluster the points have no neighbour. this way you will have access to the attributes when the feature is not in a cluster:

new OpenLayers.Strategy.Cluster({
    distance: 40,
    threshold: 1
})