12

I have an OpenLayers 3.2.0 map that features some vector sources (ol.source.Vector) and associated vector layers (ol.layer.Vector)

When Features (ol.Feature) are added to the vector sources, they are given a data property that is set to the javascript object that the feature represents. TypeScript follows...

vectorSource.addFeature(new ol.Feature({
    geometry: /* ... */,
    data: vectorData,
}));

The vector layers then have a style-function that reads the data property and retrieves its style:

vectorLayer = new ol.layer.Vector({
    source: vectorSource,
    renderBuffer: /* ... */,
    style: function (feature: ol.Feature, resolution: any) {
        var data = </* TypeScript Type */>feature.get('data');
        if ((data) && (data.style)) {
            return [data.style];
        }
        else {
            /* return default style */
        }
    }
});

Sometimes, events unrelated to the map cause the styles to change. For example, when an object becomes invalid, its style changes. Clearly, since data.style is entirely within my control, changing it is trivial.

The problem is that the map does not know that the style has changed. If I change an object's style and then zoom the map, forcing it to redraw, I notice that my style-functions run and return the new style and the feature is redrawn. How do I programatically force the map to refresh?

After some searching and experimentation, I have tried:

  1. Calling render() on the ol.Map itself.
  2. Calling dispatchChangeEvent() on the ol.source.Vector
  3. Calling redraw() on the ol.layer.Vector

These were suggested but none of them worked, which isn't surprising since only the first method is even listed in the OpenLayers 3.2.0 API documentation and it is not marked as stable.

2
  • have you tried vectorlayer.refresh({force:true}); ?
    – ylka
    Commented Feb 17, 2015 at 15:17
  • I have but, unsurprisingly, that doesn't work because that's an OpenLayers 2 method.
    – Xharlie
    Commented Feb 17, 2015 at 15:33

3 Answers 3

13

By chance, I have stumbled upon the answer - it is to call changed() on the features themselves after changing the style property of their associated data. See: http://openlayers.org/en/v3.2.0/apidoc/ol.Feature.html?unstable=true#changed

This does require me to keep track of the ol.Feature objects associated with each vectorData object (formerly, I only ever needed to find the vectorData from a feature, which could be done with get()) but this isn't much of a cost.

(I found this by looking at setGeometry and setStyle and other methods on ol.Feature to see what they do.)

1
  • 1
    Although this approach works, calling changed for any reasonable number of features actually incurs a pretty serious performance penalty (crashed Chrome a number of times this way). I'd recommend called changed() on the source of your layer after all of your features have been changed.
    – Kyle
    Commented Dec 18, 2015 at 23:27
0

I spent a week on trying to figure out how to make a feature (Polygon) disappear from the map after deleting it (vectorSource.removeFeature(selectedFeature). And no solution worked. Oddly the current OL3 v3.15.1 doesn't have basic forced-refresh/render function that works! The solution that worked for me was to change selectedFeature's style:

        var newStyle = new ol.style.Style({
            image: new ol.style.Circle({
                radius: 5,
                fill: new ol.style.Fill({color: 'red'}),
                stroke: new ol.style.Stroke({color: 'yellow', width: 1})
            })
        });
        selectedFeature.setStyle(newStyle)

Any style would work since the feature has already been removed from the layer but not refreshed.

0

Xharlie's answer helped me with the calling changed idea, except that in some cases you have to call it on the layer instead of the feature. In my case I had a style function bound to the layer and the style used a calculated geometry instead of the geometry of the feature.

layer.changed()
map.once('rendercomplete', () => {
  layer.changed()
})
map.renderSync()

ps: I actually do all this once more inside the first rendercomplete listener; and disable user interaction during this time; not ideal especially when it's long to compute so if you can avoid this kind of hack all the best for you.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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