Take the 2-minute tour ×
Geographic Information Systems Stack Exchange is a question and answer site for cartographers, geographers and GIS professionals. It's 100% free, no registration required.

I have an OpenLayers 2.12 map with a vector layer with a cluster strategy. All the static behavior is how I want it. Now I'd like to add the possibility to update the features' position. I do this with refresh code outside of the OL API, so I can easily add extra events, options lists and so related to the incoming data.

The problem is that the clustering strategy doesn't update the position for features inside a cluster. If they are not clustered, they are moved.

At first, the features are added to an array and then the array is stored and used to add all the features to the layer:

var myUnit = {
...
this.layer = new OpenLayers.Layer.Vector(
        "Voertuigen",
        {
            strategies: [
                new OpenLayers.Strategy.Cluster({
                    active: true,
                    autoActivate: true,
                    distance: this.clusterDistance,
                    threshold: this.clusterThreshold})
            ],
            styleMap: new OpenLayers.StyleMap({
                "default": style,
                "hover": hoverstyle
            }),
            isBaseLayer: false,
            rendererOptions: {yOrdering: true}
        }
    );
...
myUnit.layer.addFeatures(myUnit.features);

and for the update of the position I find the feature in myUnit.features array and move it

feature.move(pos_lonlat);

This works for all features not in a cluster. I tried many other things, including removing all the features from the layer and re-adding them. Strangely this also doesn't move the cluster.

How can i trigger the strategy to recluster everything?

share|improve this question

3 Answers 3

you should check out this answer - OpenLayers Cluster Recalculate here.

It adds a method recluster which, when called, will cause the strategy to recalculate its clustering. Since we are altering the Cluster base class, any derived class should appropriately inherit the recluster method.

i hope it helps you...

share|improve this answer
    
I did, the only difference with the original is the extra recluster function and the check in the cluster loop. If I set it to true: "if(resolution != this.resolution || !this.clustersExist() || true) {" (to force the cluster loop) it still has the same problem –  Jeroen Oct 31 '12 at 13:18
    
I might have found a problem with the feature.move call. In that function it also redraws that feature, which might be a problem. I'm looking into that now... –  Jeroen Oct 31 '12 at 13:28
    
@Jeroen: I'm having the same problem, but I've found out that vector feature which is clustered has null layer, and vector.move checks especially, if the layer is not null. Did you manage to find out solution how to move the points in clusters? –  mrówa Mar 18 '13 at 16:22
    
I've made somekind of a workaround, I've added the answer below –  Jeroen Mar 19 '13 at 14:05

In my case, I found this solution to updating features. It's working very well:

1) In javascript I create a refresh method in every 5 seconds:

window.setInterval(loadUnits, 5000);

2) Create the layer :

function createUnitsLayer() {
    var def_style = new OpenLayers.Style({
        pointRadius : "${size}",
        fillOpacity: 0.5,
    });
    var sel_style = new OpenLayers.Style({
        fillOpacity: 1
    });
    var styleMap = new OpenLayers.StyleMap({"default" : def_style, "select": sel_style});
    unitsLayer = new OpenLayers.Layer.Vector("Units",  {styleMap: styleMap} );
    map.addLayer(unitsLayer);
}

Note the unitsLayer variable is global and declared in beginning of script.

3) Now, we fill the unitsLayer with the features. These come from a AJAX request. Call this after create the map and vector, so we have the initial positions, and every 5 seconds they will be refreshed.

function loadUnits() {
    var mapbounds = map.getExtent();
    mapbounds.transform(toProjection, fromProjection );
    bbox = mapbounds.toArray();
    var bleft = bbox[0];
    var bbottom = bbox[1];
    var bright = bbox[2];
    var btop = bbox[3];
    showLoader();
    var sourceURL = "getUnits?bleft=" + bleft + "&bbottom=" + bbottom + "&bright=" + bright + "&btop=" + btop;
    $.ajax({
            url: sourceURL,
            dataType: "json"
    }).done(function(data) {
        data = eval( data );
        var geojson_format = new OpenLayers.Format.GeoJSON({
            'internalProjection': map.baseLayer.projection,
            'externalProjection': new OpenLayers.Projection("EPSG:4326")
        });
        unitsLayer.removeAllFeatures();
        unitsLayer.addFeatures(geojson_format.read(data));
    });     
}

This is a simple jQuery ajax request ( you will need the jQuery libs ) Here I set a bounding box from the map's viewport and send this to my ajax responder. If is not your case, just ignore my projection transform. Then, I remove all features from unitsLayer and add the new that came from ajax (expected a json format).

This is the expected json :

{"type":"FeatureCollection","features":[{"type":"Feature","properties":{"name":"TRON-02","serial":"TRON002","bearing":0,"color":"green","velocity":0.0,"size":15,"image":"img/unit_map3.png","pin_image":"img/pins/me/army.png","strength":0.0,"range":0.0},"geometry":{"type":"Point","coordinates":[-50.06542968749966,-23.749149728383717]}},{"type":"Feature","properties":{"name":"Magno","serial":"MAGNO","bearing":0,"color":"green","velocity":0.0,"size":15,"image":"img/unit_map3.png","pin_image":"img/pins/me/army.png","strength":0.0,"range":0.0},"geometry":{"type":"Point","coordinates":[-51.13659667968737,-25.228796984436144]}},{"type":"Feature","properties":{"name":"Flynn-01","serial":"FLYNN001","bearing":141,"color":"green","velocity":0.0,"size":15,"image":"img/unit_map3.png","pin_image":"img/pins/me/army.png","strength":0.0,"range":0.0},"geometry":{"type":"Point","coordinates":[-49.45019531249952,-26.769155570541734]}},{"type":"Feature","properties":{"name":"Stu-01","serial":"STU001","bearing":0,"color":"green","velocity":0.0,"size":15,"image":"img/unit_map3.png","pin_image":"img/pins/me/army.png","strength":0.0,"range":0.0},"geometry":{"type":"Point","coordinates":[-50.9443359374996,-26.29735617905113]}},{"type":"Feature","properties":{"name":"TRON-01","serial":"TRON001","bearing":124,"color":"green","velocity":0.0,"size":15,"image":"img/unit_map3.png","pin_image":"img/pins/me/army.png","strength":0.0,"range":0.0},"geometry":{"type":"Point","coordinates":[-49.603720399842345,-24.66298243986192]}},{"type":"Feature","properties":{"name":"Flynn-06","serial":"FLYNN006","bearing":0,"color":"green","velocity":0.0,"size":15,"image":"img/unit_map3.png","pin_image":"img/pins/me/army.png","strength":0.0,"range":0.0},"geometry":{"type":"Point","coordinates":[-48.016479492187294,-23.103987753888838]}}]}

To see well formated array you can copy and paste the data here . My ajax provider is a Java struts2 action using the Google Json library to transform a simple java bean in json.

This is the result :

enter image description here

share|improve this answer
    
Well, you've made a nice boundingbox strategy, but my problems was with the clustering of the features. Since I'll be adding many features, I do need that behavior –  Jeroen Dec 27 '12 at 8:39
    
Hum. Sory I cant help you with this. I have few points and not need cluster. I think my JQuery AJAX will not fit your needs. It's more flexible to use but not support cluser. A way to solve this is doing the job in the SQL query, but native clustering is much more easy to use. –  Magno C Jan 3 '13 at 10:24

I didn't got a good sollution, but luckaly I did add some comments what I was thinking a few months back... I copied a little bit of code and removed the part that caused trouble.

/**
 * Method: myUnit.moveFeature
 * Moves a feature to the given position. Does not redraw the layer!
 *
 * Parameters:
 * feature      {object} OpenLayers.Feature.Vector
 * lontlat      {object} OpenLayers.LonLat
 */
moveFeature: function(feature, lonlat) {
    /**
     * feature.move(lonlat) doesn't work. In the move-function 
     * there is a call to this.layer.drawfeature(feature)
     * somehow this interferes with the clustering
     * I've copied the code for updating the position from that function
     * and left out the drawFeature call.
     * Together with the custom recluster function in the OpenLayers Cluster
     * Strategy this seems to work.
     */

    var pixel;
    pixel = this.layer.getViewPortPxFromLonLat(lonlat);

    var lastPixel = this.layer.getViewPortPxFromLonLat(feature.geometry.getBounds().getCenterLonLat());
    var res = tbUnit.layer.map.getResolution();
    feature.geometry.move(res * (pixel.x - lastPixel.x), res * (lastPixel.y - pixel.y));
},

This works with the recluster posted by @Aragon

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.