Search code examples
angulartypescriptopenlayers

Openlayers: Once a layer is removed, new layers won't be added to the map


I'm a beginner so i might be overlooking something very obvious here: So i have this function, which i call with a button click, to get the layers from the map and if they are either dataLayer2 or dataLayer3 they should be removed and then dataLayer1 should be added to the map. I have the same function for the other dataLayers, which are called from the clicking on other buttons. The layers get added to the map if they are the first one to be added after loading the page. If you click on another button which should remove the active layer and add the new one, the old one gets removed from the map but the new one won't be added. I get no error or anything from the console. The data is all from the same file for all the layers. The styling is just different for the layers depending on different attributes. The geometries stay the same. I tried just loading in the layer and then restyling it with a button click but that also didn't work. Like I said I'm a beginner and might be overlooking something here.

addDataLayer1(){

this.map.getLayers().forEach(layer => {
  if (layer === this.dataLayer2 || layer === this.dataLayer3){
    this.map.removeLayer(layer);
  }
})

this.dataLayer1 = new VectorImage({ 
  source: new VectorSource({
    overlaps:false,
    features: new TopoJSON().readFeatures(file)
  })
});
this.map.addLayer(this.dataLayer1);

Solution

  • Removing items from the Layers container while iterating over it breaks its integrity (as pointed out by Mike's comment).

    This is a tempting error since it is not transparent from the Container object returned by getLayers() is implemented as an array internally.

    Adding/Removing Layers

    removeLayer() will have no effect if the layer is not part of the map. So there is not need to iterate over the layer collection and 'search' for the layers to be removed.

    addDataLayer1(){
        // simply remove the unwanted layers
        // this will have no effect if the layer to be removed is not part of the map
        this.map.removeLayer(this.dataLayer2);
        this.map.removeLayer(this.dataLayer3);
    
        // add the new layer to the map
        this.map.addLayer(this.dataLayer1);
    }
    

    The code above will add this.dataLayer1 at the end of the draw order ('z-index'). this.dataLayer1 will be drawn on top of all existing layers - potentially overdrawing exitsing layers.

    Feature Styling

    In your question you state

    The data is all from the same file for all the layers. The styling is just different for the layers depending on different attributes.

    Using different layers is not the only (probably not the best) solution for manipulating styles of a VectorLayer. Instead, you can use Feature properties to select/alter style inside the style function of the vector layer:

    // coordinates for the features
    // projected from WGS84/EPSG:4326 to Web Mercartor/EPSG:3857
    var newYorkCityCoordinates  = ol.proj.fromLonLat([-74.006111, 40.712778]);
    var washingtonDCCoordinates = ol.proj.fromLonLat([-77.016389, 38.904722]);
    
    // create a feature
    var newYorkCityFeature = new ol.Feature({
        geometry: new ol.geom.Point(newYorkCityCoordinates)
    });
    // set the style property
    newYorkCityFeature.set('circleColor', 'purple');
    
    // create a feature with style property inline 
    var washingtonDCFeature = new ol.Feature({
        geometry: new ol.geom.Point(washingtonDCCoordinates),
        circleColor: 'yellow' // this is our style property
    });
    
    // create the vector source with the two features
    var vectorSource = new ol.source.Vector({
        features: [newYorkCityFeature, washingtonDCFeature]
    });
    // create vector layer with dynamic style function
    var vectorLayer = new ol.layer.Vector({
      source: vectorSource,
      // the feature to be styled is passed to the style function
      style: function (feature, resolution) {
        return [new ol.style.Style({
          image: new ol.style.Circle({
            radius: 10,
            fill: new ol.style.Fill({
                color: feature.get('circleColor') // use style attribute for the fill color
            })
          })
        })];
      }
    });