Hi Eric,

thanks for your feedback.

Attached is an example that shows the usage and the benefits from the custom classes. I would be happy if this could be included in the OpenLayers examples.

Cheers,
Marc and Thorsten


On 04.10.2010 19:09, Eric Lemoine wrote:
On Monday, October 4, 2010, Marc Jansen<jan...@terrestris.de>  wrote:
Hi list,

the Cluster strategy decides whether two features should be grouped in a 
cluster and uses the relative distance of the features to do so. Nearby 
features are clustered, and features apart from each other are left untouched.

In a recent project we had the need to extend this behaviour, so that the 
Cluster strategy should look at the attributes of the features too, when 
deciding on clustering: only nearby features that shared an attribute should be 
clustered, otherwise, they should be left alone.

Imagine a situation where you have features with an attribute "klasse" that groups the 
features attributively. In the clustered map you only want Clusters of the same "klasse".

In our case we could solve it using different layers (requested according to their 
"klasse") and each had their own Cluster-strategy.

While we were refactoring that code a little bit we came up with the idea of 
new Cluster-subtypes: the very simple OpenLayers.Strategy.AttributeCluster and 
the more elaborate OpenLayers.Strategy.RuleCluster:

OpenLayers.Strategy.AttributeCluster = 
OpenLayers.Class(OpenLayers.Strategy.Cluster, {
     /**
      * the attribute to use for comparison
      */
     attribute: null,

     /**
      * Method: shouldCluster
      * Determine whether to include a feature in a given cluster.
      *
      * Parameters:
      * cluster - {<OpenLayers.Feature.Vector>} A cluster.
      * feature - {<OpenLayers.Feature.Vector>} A feature.
      *
      * Returns:
      * {Boolean} The feature should be included in the cluster.
      */
     shouldCluster: function(cluster, feature) {
         var cc = cluster.geometry.getBounds().getCenterLonLat();
         var fc = feature.geometry.getBounds().getCenterLonLat();
         var distance = (
             Math.sqrt(
                 Math.pow((cc.lon - fc.lon), 2) + Math.pow((cc.lat - fc.lat), 2)
             ) / this.resolution
         );
         var cc_attrval = cluster.cluster[0].attributes[this.attribute];
         var fc_attrval = feature.attributes[this.attribute];
         return (distance<= this.distance&&  cc_attrval === fc_attrval);
     },

     CLASS_NAME: "OpenLayers.Strategy.AttributeCluster"
});



OpenLayers.Strategy.RuleCluster = OpenLayers.Class(OpenLayers.Strategy.Cluster, 
{
     /**
      * the rule to use for comparison
      */
     rule: null,

     /**
      * Method: shouldCluster
      * Determine whether to include a feature in a given cluster.
      *
      * Parameters:
      * cluster - {<OpenLayers.Feature.Vector>} A cluster.
      * feature - {<OpenLayers.Feature.Vector>} A feature.
      *
      * Returns:
      * {Boolean} The feature should be included in the cluster.
      */
     shouldCluster: function(cluster, feature) {
         var cc = cluster.geometry.getBounds().getCenterLonLat();
         var fc = feature.geometry.getBounds().getCenterLonLat();
         var distance = (
             Math.sqrt(
                 Math.pow((cc.lon - fc.lon), 2) + Math.pow((cc.lat - fc.lat), 2)
             ) / this.resolution
         );
         return (distance<= this.distance&&  
this.rule.evaluate(cluster.cluster[0])&&  this.rule.evaluate(feature));
     },

     CLASS_NAME: "OpenLayers.Strategy.RuleCluster"
});

Usage Examples:

         // cluster only features that have 'klasse'<  3
         new OpenLayers.Layer.Vector('Vektorlayer 1', {
             strategies: [new OpenLayers.Strategy.Fixed(), new 
OpenLayers.Strategy.RuleCluster({
                 rule: new OpenLayers.Rule({
                     // a rule contains an optional filter
                     filter: new OpenLayers.Filter.Comparison({
                         type: OpenLayers.Filter.Comparison.LESS_THAN,
                         property: "klasse",
                         value: 3
                     })
                 })
             })],
             protocol: new OpenLayers.Protocol.HTTP({
                 url: "../data/data_001.json",
                 format: new OpenLayers.Format.GeoJSON()
             })
         });

         // cluster only features that are nearby and have the same "klasse"
         new OpenLayers.Layer.Vector('Vektorlayer 2', {
             strategies: [new OpenLayers.Strategy.Fixed(), new 
OpenLayers.Strategy.AttributeCluster({
                 rule: new OpenLayers.Rule({
                     attribute: 'klasse'
                 })
             })],
             protocol: new OpenLayers.Protocol.HTTP({
                 url: "../data/data_002.json",
                 format: new OpenLayers.Format.GeoJSON()
             })
         });


We are unsure whether this might be of interest to anybody. If so, we would be 
happy to provide patches for OpenLayers. This code currently has no tests, and 
there is room for optimization (the comparison of attributes is probably faster 
computed than the distance e.g.)

Please share your thoughts on this and tell us of alternatives we may have 
missed, or drawbacks of the outlined approach.
Your approach looks good to me, and it demonstrates well how the
cluster strategy can be extended for specific needs. To me it'd make
sense to have this code in a cluster-strategy-extended.html example or
something.

My 2 cents,


Attachment: cluster-strategy-extended.js
Description: application/javascript

Title: Extended clustering example

Extended clustering

cluster, advanced

Shows the usage of custom classes for a fine grained control about the clustering behaviour.

Select the desired clustering strategy:




The vectorlayer in this example contains random data with an attribute "clazz" that can take the values 1, 2, 3 and 4. The features with clazz = 4 are considered more important than the others.

The radiobuttons on the right of the map control the cluster strategy to be applied to the features.

  • No strategy means that all features are rendered, no clustering shall be applied
  • Simple cluster-strategy applies the cluster strategy with default options to the layer. You should notice that many of the important features with clazz = 4 are getting lost, since clustering happens regardless of feature attributes
  • Attributive cluster-strategy uses a customized cluster strategy. This strategy is configured to cluster features of the same clazz only. You should be able to see all red points (clazz = 4) even though the data is clustered. A cluster now contains only features of the same clazz.
  • Rulebased cluster-strategy uses another customized cluster strategy. This strategy is configured to cluster features that follow a certain rule only. In this case only features with a clazz different from 4 are considered as candidates for clustering. That means that usually you have fewer clusters on the map, yet all with clazz = 4 are easily distinguishable

Hover over the features to get a short infomation about the feature or cluster of features.

View the cluster-strategy-extended.js source to see how this is done.

_______________________________________________
Dev mailing list
d...@lists.osgeo.org
http://lists.osgeo.org/mailman/listinfo/openlayers-dev

Reply via email to