[GIS] How to update feature positions with clustering in OpenLayers

clusteringfeaturesopenlayers-2updatevector

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?

Best Answer

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