0
votes

A similar issue to that described in OpenLayers: destroyed features reappear after zooming in or out

Call destroyFeatures() or removeAllFeatures() (or both, in either order) on a vector layer. The features disappear from view. But then zoom in or out, and they reappear. For me, this only happens if a clustering strategy is being used. It almost seems as if the cluster feature is destroyed but the underlying features represented by that cluster are not, so, when you zoom in or out the clustering is recalculated from those underlying features and re-drawn.

Googling reveals a number of conversations among the developers of OpenLayers a few years ago concerning issues with destroyFeatures(). It's surprising that, even now, the issues don't seem to have been fully resolved.

I can get around the problem by destroying the whole layer (using destroy()) and then recreating it when needed. That's OK in my case, but I can imagine cases where such a blunderbuss approach might not be desirable.

In response to the request for a code sample, here is an abbreviated version of the code in the version that is working (ie, using destroy()). In the non-working version, I called destroyFeatures() instead (and did not set the layer to null). As stated above, this would erase the features initially, but if I then zoomed in or out using this.map.zoomIn(), the features would reappear.

Note 1: the functions are called from Objective-C via the JavaScript bridge. Note 2: the JavaScript was generated using CoffeeScript.

(function() {
  var addSightingsLayer, displayFeaturesForSightingsWithGeoJSONData, geoJSONFormat, load, map, projectionSphericalMercator, projectionWGS84, removeSightingsLayer, sightingsLayer;

  addSightingsLayer = function() {
    var context, layerStyle, layerStyleSelected, style, styleMap, styleSelected, yerClusteringStrategy;
    if (!(this.sightingsLayer === null)) return;
    yerClusteringStrategy = new OpenLayers.Strategy.Cluster({
      distance: 10,
      threshold: 2
    });
    this.sightingsLayer = new OpenLayers.Layer.Vector('Sightings', {
      strategies: [yerClusteringStrategy]
    });
    this.map.addLayer(this.sightingsLayer);
    style = {
      // Here I define a style
    };
    context = {
    // Here I define a context, with several functions depending on whether there is a cluster or not, eg:
      dependentLabel: function(feature) {
        if (feature.cluster) {
          return feature.attributes.count;
        } else {
          return feature.attributes.name;
        }
      }, ....

    };
    layerStyle = new OpenLayers.Style(style, {
      context: context
    });
    styleSelected = {
      //...
    };
    layerStyleSelected = new OpenLayers.Style(styleSelected, {
      context: context
    });
    styleMap = new OpenLayers.StyleMap({
      'default': layerStyle,
      'select': layerStyleSelected
    });
    this.sightingsLayer.styleMap = styleMap;
  };

  removeSightingsLayer = function() {
    if (this.sightingsLayer === null) return;
    this.sightingsLayer.destroy();
    return this.sightingsLayer = null;
  };

  displayFeaturesForSightingsWithGeoJSONData = function(geoJSONData) {
    if (this.sightingsLayer === null) JFOLMap.addSightingsLayer();
    return this.sightingsLayer.addFeatures(this.geoJSONFormat.read(geoJSONData));
  };

  load = function() {
    var lat, lon, osmLayer, zoom;
    lat = ...;
    lon = ...;
    zoom = ...;
    this.map = new OpenLayers.Map('mapDiv', {
      controls: ...,
      eventListeners: ...
    });
    osmLayer = new OpenLayers.Layer.OSM();
    this.map.addLayer(osmLayer);
    return this.map.setCenter(new OpenLayers.LonLat(lon,     lat).transformWGS84ToSphericalMercator(), zoom);
  };

  OpenLayers.LonLat.prototype.transformWGS84ToSphericalMercator = function() {
    return this.transform(JFOLMap.projectionWGS84, JFOLMap.projectionSphericalMercator);
  };

  OpenLayers.LonLat.prototype.transformSphericalMercatorToWGS84 = function() {
    return this.transform(JFOLMap.projectionSphericalMercator, JFOLMap.projectionWGS84);
  };

  map = null;
  sightingsLayer = null;
  sightingsPopoverControl = null;
  projectionWGS84 = new OpenLayers.Projection('EPSG:4326');
  projectionSphericalMercator = new OpenLayers.Projection('EPSG:900913');
  geoJSONFormat = new OpenLayers.Format.GeoJSON({
    'externalProjection': projectionWGS84,
    'internalProjection': projectionSphericalMercator
  });

  this.JFOLMap = {
    map: map,
    sightingsLayer: sightingsLayer,
    projectionSphericalMercator: projectionSphericalMercator,
    projectionWGS84: projectionWGS84,
    geoJSONFormat: geoJSONFormat,
    load: load,
    addSightingsLayer: addSightingsLayer,
    removeSightingsLayer: removeSightingsLayer,
    displayFeaturesForSightingsWithGeoJSONData: displayFeaturesForSightingsWithGeoJSONData,
  };

}).call(this);
1
Do you have a code example somewhere? I use the cluster strategy with destroyFeatures called dozens of times during a web app lifecycle without issue.Jeff
Thanks, Jeff. Have added code above.jfewtr
One more question, what version of OL and what config are you using if doing a custom build? Note that clustering does have a features cache, and I've seen a couple version that didn't flush it properly out there. You might want to throw a debugger; command on OpenLayer.Strategy.Cluster.clearCache() to make sure it is flushing the features cache.Jeff
I'm on v2.12, which thankfully fixed another problem I was having with tiles not redrawing properly when the viewport size changed. It's the full pre-built minified version. I just edited one line to add some extra feature shapes. Thanks for the clearCache() tip; I'll take a look at that.jfewtr
Everything else looks pretty standard. Your best bet is debugging the clearCache() function, specifically you should look at this.features Array. That is where the features are stored for the strategy...and where they should be set to null when you destroyFeatures().Jeff

1 Answers

0
votes

Try this, it worked for me

layer.removeAllFeatures();
layer.destroyFeatures();//optional
layer.addFeatures([]);