0

I'm lost with the following Situation.

I'm using OpenLayers 6 in an Android Application. I have around 4000 geoJson Features to display. It's just one vector layer with 4000 Features.

For 3000 of them, I have to set an individual text (all of them have a unique ID in a property)

When I create a Style for each feature without caching them, then my App crashes because memory usage increases to over 2GB. When I create Style and cache them by feature ID, I still have to create 3000 Styles and my app does crash also.

Now, when I cache my Styles by Color, I get 2 Styles. The app is running fine but now I can't set individual Text, because the Text is in the Style Object and I have only 2 of them.

This would be my solution if every feature gets an individual style (without caching or caching by ID).

map.once('postrender', function(event) {
    addStyle();
});


function addStyle() {
    var vectorLayer;
    var layersObject = map.getLayers();
    for (var i = 0; i < layersObject.array_.length; i++) {
        vectorLayer = layersObject.array_[i];
        break;
    }

    var arrFeatures = vectorLayer.getSource().getFeatures();
    var i = 0;
    for (i; i <= arrFeatures.length - 1; i++) {
        var feat = arrFeatures[i];
        var myId = feat.get('my_id');
        if(myId > 0){
            feat.setStyle(myStyle);
        }
    }
}

function addDescription() {

    var vectorLayer;
    var layersObject = map.getLayers();
    for (var i = 0; i < layersObject.array_.length; i++) {
        vectorLayer = layersObject.array_[i];
        break;
    }

    var arrFeatures = vectorLayer.getSource().getFeatures();
    for (var i = 1; i <= arrFeatures.length - 1; i++) {
        var feat = arrFeatures[i];
        var myId = feat.get('my_id');
        if(myId > 0){
            var description = feat.get('description')
            feat.getStyle()(feat, map.getView().getResolution()).getText().setText(description);
        }
    }
}

Is there a solution to set text without style object?

EDIT:

At the start I set only colors, without text:

var vectorLayer = new ol.layer.Vector({
            source: vectorSource,
            renderMode: 'image',
            style: function(feature) {
                style.getFill().setColor(getColorByID(feature.get('id'), feature.get('pe_nr')));
                return style;
            }
        });

And this is how I change my style and add text:

function switchStyle() {

    var vectorLayer;
    var layersObject = map.getLayers();
    for (var i = 0; i < layersObject.array_.length; i++) {
        vectorLayer = layersObject.array_[i];
        break;
    }

    if(isFoo){
        isFoo = false;
        vectorLayer.setStyle(function(feature) {
        style.getText().setText(feature.get(currentLabel));
        style.getFill().setColor(getColorByID(feature.get('id'), feature.get('pe_nr')));
        return style;
        });
    } else {
        isFoo = true;
        vectorLayer.setStyle(function(feature) {
        style.getText().setText(feature.get(currentLabel));
        style.getFill().setColor(getColor(feature.get('pe_nr')));
        return style;
        });
    }
}
BR75
  • 633
  • 7
  • 25

1 Answers1

5

Instead of setting the style of each feature, you can also define a function that returns a (dynamic) style as the style of a layer.

Have a look at this official example

The important lines are these:

var style = new Style({
  fill: new Fill({
    color: 'rgba(255, 255, 255, 0.6)'
  }),
  stroke: new Stroke({
    color: '#319FD3',
    width: 1
  }),
  text: new Text({
    font: '12px Calibri,sans-serif',
    fill: new Fill({
      color: '#000'
    }),
    stroke: new Stroke({
      color: '#fff',
      width: 3
    })
  })
});

var vectorLayer = new VectorLayer({
  source: new VectorSource({
    url: 'data/geojson/countries.geojson',
    format: new GeoJSON()
  }),
  style: function(feature) {
    style.getText().setText(feature.get('name'));
    return style;
  }
});

With the same idea you can also dynamically color your features, without creating new styles. Simply change your color-value of your Fill or Stroke inside the style-function.

Rob
  • 651
  • 3
  • 14
  • thanks. I have noticed that my app crashes when I set the text font to 24px, 18px is ok. Could you explain me why? Maybe because the text in ol is an image and takes to much memory? – BR75 Nov 26 '19 at 08:17
  • 1
    how many features are you trying to display at the same time? Performance should not really be an issue, unless you are trying to render all 4000 features at the same time with text (but then you couldn't read anything anyways). If that is the case, you can try setting a `minZoom` on your layer, use `declutter` on your layer or use a cluster-Source. But if 18px works, i don't think that thats the issue – Rob Nov 26 '19 at 09:02
  • All my features are visible at the start but not the text in the features. I set the font size as high as possible on purpose, so openlayers use declutter automatically. – BR75 Nov 26 '19 at 09:29
  • what is the desired result? you can also use the `padding` option of the text-style, so openlayers declutters more generously. 'decluttering' only means, features will be invisible when they (or their text) would overlap otherwise – Rob Nov 26 '19 at 10:39
  • I just edit my post, how it looks now and how I'm doing it. declutter for text works already. Features should not be go invisible if they overlap. My biggest problem is the performance, my app crashes sometimes when I zoom out completely and move my map rapidly. What I already tried: renderMode: 'image' for vector layer, renderer: (['webgl', 'canvas']) in map constructor and pixelRatio: Math.floor(window.devicePixelRatio || 1) – BR75 Nov 26 '19 at 11:13