[OpenLayers-Users] cluster strategy

Paul Spencer pagameba at gmail.com
Wed Feb 16 21:26:02 EST 2011


Perhaps you have uncovered a problem - when you call the deactivate method it stops further clustering from happening but I don't see anything that actually does anything to decluster the layer's features.  Here's a possible solution.  The code is untested and may contain bugs, typos, logic flaws etc.  You've been warned :)  The idea is, without having to change OpenLayers code, you can replace any property value or any method in an object by passing it as an option - so this replaces the deactivate method in the cluster strategy with one that should (and again, no promises) extract the clustered features from each feature in the layer and put back the original features.  If indeed that is what is wrong.  Please let me know if this does actually deactivate the cluster strategy and I will file a ticket and put together a proper patch with tests.

Cheers

Paul

/* Adding an Multipoint Vector Layer with cluster strategy */
var clusterStrategy = new OpenLayers.Strategy.Cluster({
    distance: 20,
    deactivate: function() {
        var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this);
        if(deactivated) {
            var features = [];
            var clusters = this.layer.features;
            for (var i=0; i<clusters.length; i++) {
              var cluster = clusters[i];
              if (cluster.cluster) {
                for (var j=0; j<cluster.cluster.length; j++) {
                  features.push(cluster.cluster[j]);
                } else {
                  features.push(cluster);
                }
              }
            }
            this.layer.removeAllFeatures();
            this.layer.events.un({
                "beforefeaturesadded": this.cacheFeatures,
                "moveend": this.cluster,
                scope: this
            });
            this.layer.addFeatures(features);
            this.clearCache();
        }
        return deactivated;
    }

});


On 2011-02-16, at 4:41 PM, Misu wrote:

> hi Paul (again) and everybody else who have a solution for this
> 
> is very strange,
> 
> console show me that the if condition is corect. Code (in my opinion) is corect. But it does not work. Cluster strategy is not deactivated / activated. any hint? Here is my code:
> 
> -----------------------------
> 
> <html>
> <head>
> <title>Cluster</title>
> <script src="js/lib/Firebug/firebug.js"></script>
> <script type="text/javascript" src="js/OpenLayers.js"></script>
> <script defer="defer" type="text/javascript">
>     function init(){
>    
>     // styles for cluster strategy   
>     var style = new OpenLayers.Style({
>                     fillColor: "${fill_color}",
>                     fillOpacity: 0.4,
>                     pointRadius: "${radius}",
>                     strokeColor: "${stroke_color}",
>                     strokeOpacity: 1,
>                     strokeWidth: 1
>                     },
>                     {
>                     context: {
>                         radius: function(feature) {
>                             var pix = 8;
>                             if(feature.cluster) {
>                                 pix = Math.min(feature.attributes.count, 11) + 8;
>                             }
>                             return pix;
>                         },
>                         fill_color: function(feature) {
>                                 if(feature.cluster) {
>                                     maxImportance = 0;
>                                     for(var c = 0; c < feature.cluster.length; c++) {
>                                         i = feature.cluster[c].attributes.importance;
>                                         if(i > maxImportance) {
>                                             maxImportance = i;
>                                             mainFeature = c;
>                                         }
>                                     }
>                                     feature.attributes.fillColor = feature.cluster[mainFeature].attributes.fillColor;
>                                 }
>                                 return feature.attributes.fillColor;
>                         },
>                         stroke_color: function(feature) {
>                                 if(feature.cluster) {
>                                     maxImportance = 0;
>                                     for(var c = 0; c < feature.cluster.length; c++) {
>                                         i = feature.cluster[c].attributes.importance;
>                                         if(i > maxImportance) {
>                                             maxImportance = i;
>                                             mainFeature = c;
>                                         }
>                                     }
>                                     feature.attributes.strokeColor = feature.cluster[mainFeature].attributes.strokeColor;
>                                 }
>                                 return feature.attributes.strokeColor;
>                         }
>                     }
>     });
>                 
>     /* Creating the Map Viewer */
>         /*In order to create the viewer, you must first create a map. The OpenLayers.Map constructor requires one argument: This argument must either be an HTML Element, or the ID of an HTML element. This is the element in which the map will be placed.*/
>     var map = new OpenLayers.Map("map", {
>         controls: [
>             new OpenLayers.Control.Navigation(),
>             new OpenLayers.Control.PanPanel(),
>             new OpenLayers.Control.ZoomPanel(),
>             new OpenLayers.Control.LayerSwitcher()        /* Open the switch layers panel */
>         ],
>         maxResolution: 'auto'/*,
>         numZoomLevels: 6        // levels of zoom*/
>     });
>     
>     
>    
>     /*Map Constructor*/
>         /* The next step to creating a viewer is to add a basic layer to the Map. */
>     var basicMapLayer = new OpenLayers.Layer.Image(
>           "Map Image",
>           "images/maps/MapImage.jpg",
>           new OpenLayers.Bounds(0, 0, 510, 510),
>         new OpenLayers.Size(510, 510)
>      );
>    
>     /* Adding an Multipoint Vector Layer with cluster strategy */
>     var clusterStrategy = new OpenLayers.Strategy.Cluster({distance: 20});
>    
>     var monuments = new OpenLayers.Layer.Vector("Monuments", {
>                         strategies: [clusterStrategy],
>                         styleMap: new OpenLayers.StyleMap({"default": style})
>                     });
>    
>     // cluster threshold
>     var clusterMaxZoom = 0; // maximum zoom level is 6
>     
>     map.events.register("move", null, function() {  // respond to map extent change
>         
>         var zoom = map.getZoom();
>         console.log('zoom is ' + zoom);
>         
>         // disable cluster when zoom greater than threshold
>           if (zoom > clusterMaxZoom) {  // read current zoom
>             clusterStrategy.deactivate();      // disable cluster strategy
>             //clusterStrategy.clearCache();    // clear cluster cache
>             console.log('should deactivate cluster');
>          } else {
>             clusterStrategy.activate();        // disable cluster strategy
>             console.log('should activate cluster');
>          }
>     });
>    
>    
>    // create vector points to be added to layer
>     var point_1 = new OpenLayers.Geometry.Point(270, 205);   
>             var point_1_Feature = new OpenLayers.Feature.Vector(point_1);
>             point_1_Feature.attributes = {
>                 strokeColor: "#ffffff",
>                 fillColor: "#ffffff",
>                 importance: 9
>             }
>  
>     var point_2 = new OpenLayers.Geometry.Point(263, 201);   
>        var point_2_Feature = new OpenLayers.Feature.Vector(point_2);
>             point_2_Feature.attributes = {
>                 strokeColor: "blue",
>                 fillColor: "blue",
>                 importance: 3
>             }
>    
>     var point_3 = new OpenLayers.Geometry.Point(260, 202);
>            var point_3_Feature = new OpenLayers.Feature.Vector(point_3);
>             point_3_Feature.attributes = {
>                 strokeColor: "yellow",
>                 fillColor: "yellow",
>                 importance: 5
>             }
>    
>     var point_4 = new OpenLayers.Geometry.Point(261, 202);
>            var point_4_Feature = new OpenLayers.Feature.Vector(point_4);
>             point_4_Feature.attributes = {
>                 strokeColor: "yellow",
>                 fillColor: "yellow",
>                 importance: 5
>             }
>    
>     var point_5 = new OpenLayers.Geometry.Point(263, 202);
>         var point_5_Feature = new OpenLayers.Feature.Vector(point_5);
>             point_5_Feature.attributes = {
>                 strokeColor: "yellow",
>                 fillColor: "yellow",
>                 importance: 5
>             }
>    
>     /* Layer Constructor */
>         /* In order to display the map, you must set a center and zoom level. In order to zoom to fit the map into the window, you can use the zoomToMaxExtent function, which will zoom as close as possible while still fitting the full extents within the window. */
>     map.addLayers([basicMapLayer, monuments]);
>     map.zoomToMaxExtent();
>  
>         // features for layer with cluster strategy must me declared after layer is added in order to work
>         var monumentsFeature = new OpenLayers.Feature.Vector(
>                                     new OpenLayers.Geometry.MultiPoint([point_1, point_2, point_3, point_4, point_5])
>                                 );
>         monuments.addFeatures([point_1_Feature, point_2_Feature, point_3_Feature, point_4_Feature, point_5_Feature]);
>     
>     
>    
>     // end of init function
>     }
> </script>
> </head>
> <body onLoad="init()">
> <div style="width:100%; height:100%; border:#000 1px solid; background:#000000;" id="map"></div>
> </body>
> </html>
> 
> ----------------------------
> 
> On Wed, Feb 16, 2011 at 5:21 PM, Paul Spencer <pagameba at gmail.com> wrote:
> change it to be
> 
> var zoom = map.getZoom();
> console.log('zoom is ' + zoom);
> if (zoom < clusterMaxZoom)
> 
> so that you can see what the actual zoom levels are.
> 
> On 2011-02-16, at 9:54 AM, Mihai Visan wrote:
> 
> > Hi Paul,
> >
> > from what I know about OpenLayers your code is what I'm looking for, but I can't make the event working. What is interesting is that if I change what is with red it deactivate cluster strategy no matter the zoom level.
> >
> > map.events.register("move", null, function() {  // #2, #3 respond to map extent change
> >        // disable cluster when zoom greater than threshold
> >          if (map.getZoom() < clusterMaxZoom) {  // #2.1 how to read current zoom
> >            clusterStrategy.deactivate();  // #2.2 how to disable cluster strategy
> >         } else {
> >            clusterStrategy.activate();
> >         }
> >    });
> >
> > Help me please.
> >
> > Here is my code:
> >
> > ....................................................................
> >
> > <html>
> > <head>
> > <title>OpenLayers Test</title>
> > <script type="text/javascript" src="js/OpenLayers.js"></script>
> > <script defer="defer" type="text/javascript">
> >     function init(){
> >
> >     // styles for cluster strategy
> >     var style = new OpenLayers.Style({
> >                     fillColor: "${fill_color}",
> >                     fillOpacity: 0.4,
> >                     pointRadius: "${radius}",
> >                     strokeColor: "${stroke_color}",
> >                     strokeOpacity: 1,
> >                     strokeWidth: 1
> >                     },
> >                     {
> >                     context: {
> >                         radius: function(feature) {
> >                             var pix = 8;
> >                             if(feature.cluster) {
> >                                 pix = Math.min(feature.attributes.count, 11) + 8;
> >                             }
> >                             return pix;
> >                         },
> >                         fill_color: function(feature) {
> >                                 if(feature.cluster) {
> >                                     maxImportance = 0;
> >                                     for(var c = 0; c < feature.cluster.length; c++) {
> >                                         i = feature.cluster[c].attributes.importance;
> >                                         if(i > maxImportance) {
> >                                             maxImportance = i;
> >                                             mainFeature = c;
> >                                         }
> >                                     }
> >                                     feature.attributes.fillColor = feature.cluster[mainFeature].attributes.fillColor;
> >                                 }
> >                                 return feature.attributes.fillColor;
> >                         },
> >                         stroke_color: function(feature) {
> >                                 if(feature.cluster) {
> >                                     maxImportance = 0;
> >                                     for(var c = 0; c < feature.cluster.length; c++) {
> >                                         i = feature.cluster[c].attributes.importance;
> >                                         if(i > maxImportance) {
> >                                             maxImportance = i;
> >                                             mainFeature = c;
> >                                         }
> >                                     }
> >                                     feature.attributes.strokeColor = feature.cluster[mainFeature].attributes.strokeColor;
> >                                 }
> >                                 return feature.attributes.strokeColor;
> >                         }
> >                     }
> >     });
> >
> >     /* Creating the Map Viewer */
> >         /*In order to create the viewer, you must first create a map. The OpenLayers.Map constructor requires one argument: This argument must either be an HTML Element, or the ID of an HTML element. This is the element in which the map will be placed.*/
> >     var map = new OpenLayers.Map("map", {
> >         controls: [
> >             new OpenLayers.Control.Navigation(),
> >             new OpenLayers.Control.PanPanel(),
> >             new OpenLayers.Control.ZoomPanel(),
> >             new OpenLayers.Control.LayerSwitcher()        /* Open the switch layers panel */
> >         ],
> >         maxResolution: 'auto',
> >         numZoomLevels: 6        // maximum zoom
> >     });
> >
> >     /*Map Constructor*/
> >         /* The next step to creating a viewer is to add a basic layer to the Map. */
> >     var basicMapLayer = new OpenLayers.Layer.Image(
> >           "Map Image",
> >           "images/maps/MapImage.jpg",
> >           new OpenLayers.Bounds(0, 0, 510, 510),
> >         new OpenLayers.Size(510, 510)
> >      );
> >
> >     /* Adding an Multipoint Vector Layer with cluster strategy */
> >     var clusterStrategy = new OpenLayers.Strategy.Cluster({distance: 20});
> >
> >     var monuments = new OpenLayers.Layer.Vector("Monuments", {
> >                         strategies: [clusterStrategy],
> >                         styleMap: new OpenLayers.StyleMap({"default": style})
> >                     });
> >
> >     // cluster threshold
> >     var clusterMaxZoom = 2; // maximum zoom is 6
> >
> >     map.events.register("move", null, function() {  // #2, #3 respond to map extent change
> >         // disable cluster when zoom greater than threshold
> >           if (map.getZoom() > clusterMaxZoom) {  // #2.1 how to read current zoom
> >             clusterStrategy.deactivate();  // #2.2 how to disable cluster strategy
> >          } else {
> >             clusterStrategy.activate();
> >          }
> >     });
> >
> >     var point_1 = new OpenLayers.Geometry.Point(270, 205);
> >             var point_1_Feature = new OpenLayers.Feature.Vector(point_1);
> >             point_1_Feature.attributes = {
> >                 strokeColor: "#ffffff",
> >                 fillColor: "#ffffff",
> >                 importance: 9
> >             }
> >
> >     var point_2 = new OpenLayers.Geometry.Point(263, 201);
> >         var point_2_Feature = new OpenLayers.Feature.Vector(point_2);
> >             point_2_Feature.attributes = {
> >                 strokeColor: "blue",
> >                 fillColor: "blue",
> >                 importance: 3
> >             }
> >
> >        var point_3 = new OpenLayers.Geometry.Point(260, 202);
> >             var point_3_Feature = new OpenLayers.Feature.Vector(point_3);
> >             point_3_Feature.attributes = {
> >                 strokeColor: "yellow",
> >                 fillColor: "yellow",
> >                 importance: 5
> >             }
> >
> >     var point_4 = new OpenLayers.Geometry.Point(261, 202);
> >             var point_4_Feature = new OpenLayers.Feature.Vector(point_4);
> >             point_4_Feature.attributes = {
> >                 strokeColor: "yellow",
> >                 fillColor: "yellow",
> >                 importance: 5
> >             }
> >
> >     var point_5 = new OpenLayers.Geometry.Point(263, 202);
> >             var point_5_Feature = new OpenLayers.Feature.Vector(point_5);
> >             point_5_Feature.attributes = {
> >                 strokeColor: "yellow",
> >                 fillColor: "yellow",
> >                 importance: 5
> >             }
> >
> >     /* Layer Constructor */
> >         /* In order to display the map, you must set a center and zoom level. In order to zoom to fit the map into the window, you can use the zoomToMaxExtent function, which will zoom as close as possible while still fitting the full extents within the window. */
> >     map.addLayers([basicMapLayer, monuments]);
> >     map.zoomToMaxExtent();
> >
> >         // features for layer with cluster strategy must me declared after layer is added in order to work
> >         var monumentsFeature = new OpenLayers.Feature.Vector(
> >                                     new OpenLayers.Geometry.MultiPoint([point_1, point_2, point_3, point_4, point_5])
> >                                 );
> >         monuments.addFeatures([point_1_Feature, point_2_Feature, point_3_Feature, point_4_Feature, point_5_Feature]);
> >
> >     // end of init function
> >     }
> > </script>
> > </head>
> > <body onLoad="init()">
> > <div style="width:100%; height:100%; border:#000 1px solid; background:#000000;" id="map"></div>
> > </body>
> > </html>
> >
> > ....................................................................
> >
> > -----Original Message-----
> > From: Paul Spencer
> > Sent: Wednesday, February 16, 2011 3:37 PM
> > To: Mihai Visan
> > Cc: OpenLayers User list
> > Subject: Re: [OpenLayers-Users] cluster strategy
> >
> > I don't know your code but I would assume that you are looking for something like this:
> >
> > var map = new OpenLayers.Map('mapDiv', mapOptions);
> > var clusterStrategy = new OpenLayers.Strategy.Cluster(clusterOptions);
> > var layerOptions = {
> >   strategies: [clusterStrategy]
> > };
> > var vectorLayers = new OpenLayers.Layer.Vector('features', layerOptions);
> >
> > // cluster threshold
> > var clusterMaxZoom = 10;
> >
> > map.events.register('move', null, function() {  // #2, #3 respond to map extent change
> >   // disable cluster when zoom greater than threshold
> >   if (map.getZoom() > clusterMaxZoom) {  // #2.1 how to read current zoom
> >     clusterStrategy.deactivate();  // #2.2 how to disable cluster strategy
> >   } else {
> >     clusterStrategy.activate();
> >   }
> >
> >   // filter features based on bounding box
> >   var extent = map.getExtent();  // #3.1
> >
> >   // reload features here, it depends on how you read your features in now
> >
> > });
> >
> > If you are not using a Protocol like WFS () with your layer then the BBOX strategy will have no effect and you will have to manually reload features using whatever mechanism you are using now.
> >
> > Cheers
> >
> > Paul
> >
> > On 2011-02-16, at 7:58 AM, Mihai Visan wrote:
> >
> > > Thanks Paul,
> > >
> > > I already read the documentation and all tutorial and user discusions I could found.
> > >
> > > But I'm a week at javascript, so I could use some examples or tutorials  I could transform
> > >
> > > -----Original Message----- From: Paul Spencer
> > > Sent: Wednesday, February 16, 2011 2:43 PM
> > > To: Mihai Visan
> > > Subject: Re: [OpenLayers-Users] cluster strategy
> > >
> > > Mihai, all of your questions have answers in the documentation ...
> > >
> > > On 2011-02-16, at 7:29 AM, Mihai Visan wrote:
> > >
> > >> 2. disable cluster strategy at certain zoom level.
> > >>    Problems:     2.1. I don’t know how to read current zoom
> > >
> > > http://dev.openlayers.org/releases/OpenLayers-2.10/doc/apidocs/files/OpenLayers/Map-js.html#OpenLayers.Map.getZoom
> > >
> > >>                        2.2. I don’t know to disable cluster strategy
> > >
> > > http://dev.openlayers.org/releases/OpenLayers-2.10/doc/apidocs/files/OpenLayers/Strategy/Cluster-js.html#OpenLayers.Strategy.Cluster.deactivate
> > >
> > >>
> > >> 3. use (BBOX strategy and) ajax to disable features outside visible bounds
> > >>    Problems:    3.1. I don’t know how to read visible bounds
> > >
> > > http://dev.openlayers.org/releases/OpenLayers-2.10/doc/apidocs/files/OpenLayers/Map-js.html#OpenLayers.Map.getExtent
> > >
> > >>                       3.2. I don’t know  how to integrate ajax with (BBOX and) mouse drag or zoom in/out
> > >
> > > http://dev.openlayers.org/releases/OpenLayers-2.10/doc/apidocs/files/OpenLayers/Map-js.html#OpenLayers.Map.EVENT_TYPES
> > >
> > > Cheers
> > >
> > > Paul
> >
> 
> 



More information about the Users mailing list