javascriptionic-frameworkopenlayersopenlayers-5

Removing markers and clear sources not working. The markers remain on the map


I inherited this code of an openlayers map, but I am not able to remove all markers to reset the map and redraw.
I added the resetMap function at the end of the file:

declare var ol: any;

export class OpenLayersService {

  private markers: any[] = [];
  public layers: any[] = [];
  public markerVectorLayer : any;
  public vectorSource : any ;
  private findMe: boolean;
  private lastLat: any;
  private lastLon: any;
  private vectorMyPositionLayer: any; 
  private markersClusterLayer;

  static addDistrictCenter(lat, lng, map, label) {
    const vectorLayer = new ol.layer.Vector({
      source: new ol.source.Vector({
        features: [
          new ol.Feature({
            geometry: new ol.geom.Point(
                ol.proj.transform(
                    [parseFloat(lng), parseFloat(lat)],
                    'EPSG:4326',
                    'EPSG:3857'
                )
            )
          }),
        ]
      }),
      minResolution: 2,
      maxResolution: 10,
      style: new ol.style.Style({
        text: new ol.style.Text({
          offsetY: 13,
          text: label,
          font: '13px Lato',
          scale: 1,
          textAlign: 'center',
          textBaseline: 'middle',
          fill: new ol.style.Fill({
            color: 'white'
          }),
          stroke: new ol.style.Stroke({
            color: 'black',
             width: 3
          })
        })
      })
    });

    map.addLayer(vectorLayer);
  }

  initMap(lat: number, lon: number, target: string) {
    this.vectorSource = new ol.source.Vector({
      features: [],
      
      style: new ol.style.Style({
        image: new ol.style.Icon({
          anchor: [0.5, 0.5],
          anchorXUnits: "fraction",
          anchorYUnits: "fraction",
          src: "https://upload.wikimedia.org/wikipedia/commons/e/ec/RedDot.svg"
        })
      })
    });

    this.markerVectorLayer = new ol.layer.Vector({
      source: this.vectorSource,
      minResolution: 0,
      maxResolution: 1.2
    });

    const map = new ol.Map({
      interactions: ol.interaction.defaults({
        doubleClickZoom: true,
        dragAndDrop: false,
        dragPan: true,
        keyboardPan: false,
        keyboardZoom: false,
        mouseWheelZoom: true,
        pointer: false,
        select: false,
      }),
      target: target,
      layers: [
        new ol.layer.Tile({
          visible: true,
          source: new ol.source.XYZ({
            url: 'https://cartodb-basemaps-a.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png',
          })
        }),this.markerVectorLayer
      ,],
      view: new ol.View({
        maxZoom: 24,
        minZoom: 6,
        zoom: 15,
        center: ol.proj.fromLonLat([lon, lat])
      }),
      controls: [],
      loadTilesWhileAnimating: true
    });

    OpenLayersService.addDistrictCenter(lat, lon, map, 'MY CENTER');
    this.addDistrict(lat, lon, map);
    map.updateSize();

    return map;
  }

  styleFunction(label) {
    return new ol.style.Style({
      image: new ol.style.Circle({
        radius: 8,
        stroke: new ol.style.Stroke({
          color: '#fff',
          width: 2
        }),
        fill: new ol.style.Fill({
          color: '#343434'
        })
      }),
      text: new ol.style.Text({
        offsetY: 17,
        text: label,
        font: '13px Lato',
        scale: 1.3,
        textAlign: 'center',
        textBaseline: 'middle',
        fill: new ol.style.Fill({
          color: 'black'
        }),
        stroke: new ol.style.Stroke({
          color: '#FEFEFE',
          width: 2
        })
      })
    });
  }

  addMarker(lat, lng, map, label, nodeid) {
    const point = new ol.geom.Point(
        ol.proj.transform(
            [parseFloat(lng), parseFloat(lat)],
            'EPSG:4326',
            'EPSG:3857'
        )
    );
    this.markers.push(point);
  
    const marker = new ol.Feature({
      geometry: point
    });
    marker.setStyle(this.styleFunction(label));
    
    marker.set('id', nodeid+1);

    this.vectorSource.addFeature(marker);
    return marker;
  }

  center(lat, lon, map) {
    if (this.vectorMyPositionLayer) {
      map.removeLayer(this.vectorMyPositionLayer);
    }

    const point = new ol.geom.Point(
          ol.proj.transform(
              [parseFloat(lon), parseFloat(lat)],
              'EPSG:4326',
              'EPSG:3857'
          )
      );

      this.vectorMyPositionLayer = new ol.layer.Vector({
        source: new ol.source.Vector({
          features: [
            new ol.Feature({
              geometry: point
            }),
          ]
        }),
        style: new ol.style.Style({
          image: new ol.style.Circle({
            radius: 8,
            stroke: new ol.style.Stroke({
              color: '#fff',
              width: 2
            }),
            fill: new ol.style.Fill({
              color: '#b52218'
            })
          }),
          text: new ol.style.Text({
            offsetY: 17,
            font: '13px Lato',
            scale: 1.3,
            textAlign: 'center',
            textBaseline: 'middle',
            fill: new ol.style.Fill({
              color: 'black'
            }),
            stroke: new ol.style.Stroke({
              color: '#FEFEFE',
              width: 2
            })
          })
        })
      });

      map.addLayer(this.vectorMyPositionLayer);
      
      const location = ol.proj.transform([lon, lat], 'EPSG:4326', 'EPSG:3857');

      const dettaglio = new ol.View({
        minZoom: 6,
        maxZoom: 24,
        zoom: 17,
        center: location,
        duration: 200
      });
      map.setView(dettaglio);
  }

  resetCenter(lat, lon, map) {
    const location = ol.proj.transform([lon, lat], 'EPSG:4326', 'EPSG:3857');

    const dettaglio = new ol.View({
      minZoom: 6,
      maxZoom: 24,
      zoom: 17,
      center: location,
      duration: 200
    });
    
    map.setView(dettaglio);
  }

  addDistrict(lat: number, lon: number, map) {
    const COORD_SYSTEM_GPS = 'EPSG:4326';  // gps (long/lat) coord system..
    const COORD_SYSTEM_OSM = 'EPSG:3857';  // SphericalMercatorCoords - google and OSM's coord system..

    // styles for the vector layers
    const styles = [
      new ol.style.Style({
        stroke: new ol.style.Stroke({
          color: 'rgba(156,156,156,1)',
          width: 0
        }),
        fill: new ol.style.Fill({
          color: 'rgba(0,0,0,0.1)'
        })
      }),
      new ol.style.Style({
        image: new ol.style.Circle({
          radius: 0,
          fill: new ol.style.Fill({
            color: 'orange'
          })
        }),
        geometry: function (feature) {
          // return the coordinates of the first ring of the polygon
          const coordinates = feature.getGeometry().getCoordinates()[0];
          return new ol.geom.MultiPoint(coordinates);
        }
      })
    ];

    // Create new layer/s
    const numLayers = 1;
    const vectorSource = [];
    const vectorLayer = [];
    const layerGroup = [];
    for (let i = 0; i < numLayers; i++) {
      vectorSource[i] = new ol.source.Vector({});
      vectorLayer[i] = new ol.layer.Vector({
        source: vectorSource[i],
        style: styles
      });
      layerGroup[i] = new ol.layer.Group({
        layers: [vectorLayer[i]],
      });
      map.addLayer(layerGroup[i]);
    }

    let layerIndex = 0;

    const featureCollection = {
      'type': 'FeatureCollection',
      'totalFeatures': 5,
      'features': [
        {
          'type': 'Feature',
          'id': 'feature-001',
          'geometry': {
            'type': 'Polygon',
            'coordinates': [[
              [...lat..., ...lng...],
            ]],
          },
          'geometry_name': 'xxx',
          'properties': {}
        }
      ]
    };

    featureCollection.features.forEach(function (featureJson) {
      const feature = new ol.Feature({
        geometry: (new ol.geom.Polygon(featureJson.geometry.coordinates)).transform(COORD_SYSTEM_GPS, COORD_SYSTEM_OSM)
      });
      // Add feature to the vector source..
      vectorSource[layerIndex].addFeature(feature);
    });
  }

  addCluster(map) {
    const features = [];
    for (let i = 0; i < this.markers.length; ++i) {
      features[i] = new ol.Feature(
          {
            geometry: this.markers[i]
          }
      );
    }

    const source = new ol.source.Vector({
      features: features
    });

    const clusterSource = new ol.source.Cluster({
      source: source
    });

    const styleCache = {};
    this.markersClusterLayer = new ol.layer.Vector({
      source: clusterSource,
      style: function(feature) {
        const zoom = map.getView().getZoom();
        const size = feature.get('features').length;
        let style = styleCache[size];
        if (size === 1) {
          style = new ol.style.Style({
            image: new ol.style.Circle({
              radius: 8,
              stroke: new ol.style.Stroke({
                color: '#fff',
                width: 2
              }),
              fill: new ol.style.Fill({
                color: '#343434'
              })
            })
          });
          styleCache[size] = style;
        } else {
          style = new ol.style.Style({
            image: new ol.style.Circle({
              radius: 13,
              stroke: new ol.style.Stroke({
                color: '#fff',
                width: 2
              }),
              fill: new ol.style.Fill({
                color: '#343434'
              })
            }),
            text: new ol.style.Text({
              text: size.toString(),
              fill: new ol.style.Fill({
                color: '#fff',
                font: '14px'
              })
            })
          });
          styleCache[size] = style;
        }
        return style;
      }
    });

    map.addLayer(this.markersClusterLayer);
  }

  ///
  /// I added this function but it does not work
  ///
  resetMap() {
    this.markers = [];
    if (this.markersClusterLayer) {
      this.markersClusterLayer.getSource().clear();
    }
    if (this.vectorSource) {
      this.vectorSource.clear();
    }
    if (this.markerVectorLayer) {
      this.markerVectorLayer.getSource().clear();
    }
  }
}

This is the code to add markers (I call initMap before that):

this.olService.resetMap();

for (let i = 0; i < records.length; i++) {
    if (!records[i].latitude || !records[i].longitude) {
        continue;
    }
    const marker = this.olService.addMarker(records[i].latitude, records[i].longitude, this.map, records[i].title, i+1);
}

this.olService.addCluster(this.map);

When I get new markers from the web (for example 0 records, so I expect to not have any markers on the map), the map is redrawn but the markers remain.


Solution

  • I solved.
    The problem was I was adding new layer of markers without deleting old one.

    This is the new version of addCluster function, where first of all I name the cluster, and I remove it (if exists) before adding new one:

    addCluster(map, deleteOld : boolean = true) {
        if (deleteOld) {
          // HERE I DELETE OLD ONE BEFORE ADDING NEW ONE
          map.getLayers().getArray()
                .filter(layer => layer.get('name') === 'Markers')
                .forEach(layer => map.removeLayer(layer));
        }
    
        const features = [];
        for (let i = 0; i < this.markers.length; ++i) {
          features[i] = new ol.Feature(
              {
                geometry: this.markers[i]
              }
          );
        }
    
        const source = new ol.source.Vector({
          features: features
        });
    
        const clusterSource = new ol.source.Cluster({
          source: source
        });
    
        const styleCache = {};
        this.markersClusterLayer = new ol.layer.Vector({
          source: clusterSource,
          style: function(feature) {
            const zoom = map.getView().getZoom();
            const size = feature.get('features').length;
            let style = styleCache[size];
            if (size === 1) {
              style = new ol.style.Style({
                image: new ol.style.Circle({
                  radius: 8,
                  stroke: new ol.style.Stroke({
                    color: '#fff',
                    width: 2
                  }),
                  fill: new ol.style.Fill({
                    color: '#343434'
                  })
                })
              });
              styleCache[size] = style;
            } else {
              style = new ol.style.Style({
                image: new ol.style.Circle({
                  radius: 13,
                  stroke: new ol.style.Stroke({
                    color: '#fff',
                    width: 2
                  }),
                  fill: new ol.style.Fill({
                    color: '#343434'
                  })
                }),
                text: new ol.style.Text({
                  text: size.toString(),
                  fill: new ol.style.Fill({
                    color: '#fff',
                    font: '14px'
                  })
                })
              });
              styleCache[size] = style;
            }
            return style;
          }
        });
        this.markersClusterLayer.set('name', 'Markers');
    
        map.addLayer(this.markersClusterLayer);
    }