Search code examples
openlayersopenlayers-5

Continue zooming in when smaller clusters are tapped


I am using openlayers 5.3. I want to continue zooming in when smaller clusters are tapped or clicked. I have used some code to achieve such requirement but it doesn't work.

getStyleForCluster = (size: number): ol.style.Style => {
    let clusterStyle = (<any>window).styleCache[size];
    if (!clusterStyle) {

        clusterStyle = new ol.style.Style({
            image: new ol.style.Circle({
                radius: (Math.log(size) / Math.log(10)) * 3 + 10,
                fill: new ol.style.Fill({
                    color: this.getFillColorForPlace(size)
                })
            }),
            text: new ol.style.Text({
                text: size.toString(),
                fill: new ol.style.Fill({
                    color: "#fff"
                })
            })
        });

        (<any>window).styleCache[size] = clusterStyle;
    }
    return clusterStyle;
}


this.ClusterSource = new ol.source.Cluster({
      distance: distance,
      source: vectorSource
});

 var vectorLayer = new ol.layer.Vector({
       renderMode: 'image',
       source: this.ClusterSource,
       style: this.styleFunction,
       zIndex: 9999
 });

could you please suggest me how to resolve such issue.


Solution

  • If you mean zoom in on a cluster when it is clicked you could get the extents of the features within the cluster and fit the map to that. Here is an example of doing that (using zoomCluster function added to this example https://openlayers.org/en/v4.6.5/examples/cluster.html )

      var distance = document.getElementById('distance');
    
      var count = 20000;
      var features = new Array(count);
      var e = 4500000;
      for (var i = 0; i < count; ++i) {
        var coordinates = [2 * e * Math.random() - e, 2 * e * Math.random() - e];
        features[i] = new ol.Feature(new ol.geom.Point(coordinates));
      }
    
      var source = new ol.source.Vector({
        features: features
      });
    
      var clusterSource = new ol.source.Cluster({
        distance: parseInt(distance.value, 10),
        source: source
      });
    
      var styleCache = {};
      var clusters = new ol.layer.Vector({
        source: clusterSource,
        style: function(feature) {
          var size = feature.get('features').length;
          var style = styleCache[size];
          if (!style) {
            style = new ol.style.Style({
              image: new ol.style.Circle({
                radius: 10,
                stroke: new ol.style.Stroke({
                  color: '#fff'
                }),
                fill: new ol.style.Fill({
                  color: '#3399CC'
                })
              }),
              text: new ol.style.Text({
                text: size.toString(),
                fill: new ol.style.Fill({
                  color: '#fff'
                })
              })
            });
            styleCache[size] = style;
          }
          return style;
        }
      });
    
      var raster = new ol.layer.Tile({
        source: new ol.source.OSM()
      });
    
      var map = new ol.Map({
        layers: [raster, clusters],
        target: 'map',
        view: new ol.View({
          center: [0, 0],
          zoom: 2
        })
      });
    
      distance.addEventListener('input', function() {
        clusterSource.setDistance(parseInt(distance.value, 10));
      });
    
      var zoomCluster = function(pixel) {
    
        var feature = map.forEachFeatureAtPixel(pixel, function(feature) {
          return feature;
        });
    
        if (feature) {
    
          var features = feature.get('features');
          if (features.length > 1) {
    
            var extent = ol.extent.createEmpty();
            features.forEach(function(feature) {
              ol.extent.extend(extent, feature.getGeometry().getExtent());
            });
            map.getView().fit(extent);
    
          }
    
        }
    
      };
    
      map.on('click', function(evt) {
        zoomCluster(evt.pixel);
      });
    .map (
      width: 100%;
      height: 80%;
    }
    <link rel="stylesheet" href="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/css/ol.css" type="text/css">
    <script src="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/build/ol.js"></script>
    <div id="map" class="map"></div>
    <form>
      <label>cluster distance</label>
      <input id="distance" type="range" min="0" max="100" step="1" value="40"/>
    </form>

    This version cancels the zoom if individual pins cannot be displayed:

      var distance = document.getElementById('distance');
    
      var count = 20000;
      var features = new Array(count);
      var e = 4500000;
      for (var i = 0; i < count; ++i) {
        var coordinates = [2 * e * Math.random() - e, 2 * e * Math.random() - e];
        features[i] = new ol.Feature(new ol.geom.Point(coordinates));
      }
    
      var source = new ol.source.Vector({
        features: features
      });
    
      var clusterSource = new ol.source.Cluster({
        distance: parseInt(distance.value, 10),
        source: source
      });
    
      var styleCache = {};
      var clusters = new ol.layer.Vector({
        source: clusterSource,
        style: function(feature) {
          var size = feature.get('features').length;
          var style = styleCache[size];
          if (!style) {
            style = new ol.style.Style({
              image: new ol.style.Circle({
                radius: 10,
                stroke: new ol.style.Stroke({
                  color: '#fff'
                }),
                fill: new ol.style.Fill({
                  color: '#3399CC'
                })
              }),
              text: new ol.style.Text({
                text: size.toString(),
                fill: new ol.style.Fill({
                  color: '#fff'
                })
              })
            });
            styleCache[size] = style;
          }
          return style;
        }
      });
    
      var raster = new ol.layer.Tile({
        source: new ol.source.OSM()
      });
    
      var map = new ol.Map({
        layers: [raster, clusters],
        target: 'map',
        view: new ol.View({
          center: [0, 0],
          zoom: 2
        })
      });
    
      distance.addEventListener('input', function() {
        clusterSource.setDistance(parseInt(distance.value, 10));
      });
    
      var zoomCluster = function(pixel) {
    
        var feature = map.forEachFeatureAtPixel(pixel, function(feature) {
          return feature;
        });
    
        if (feature) {
    
          var features = feature.get('features');
          if (features.length > 1) {
    
            var oldExtent = map.getView().calculateExtent();
            var extent = ol.extent.createEmpty();
            features.forEach(function(feature) {
              ol.extent.extend(extent, feature.getGeometry().getExtent());
            });
            map.getView().fit(extent, {
              callback: function() {
                var feature = clusterSource.forEachFeatureInExtent(extent, function(feature) {
                  if (feature.get('features').length > 1) {
                    return feature;
                  }
                });
                if (feature) {
                  map.getView().fit(oldExtent);
                }
              }
            });
    
          }
    
        }
    
      };
    
      map.on('click', function(evt) {
        zoomCluster(evt.pixel);
      });
    .map (
      width: 100%;
      height: 80%;
    }
    <link rel="stylesheet" href="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/css/ol.css" type="text/css">
    <script src="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/build/ol.js"></script>
    <div id="map" class="map"></div>
    <form>
      <label>cluster distance</label>
      <input id="distance" type="range" min="0" max="100" step="1" value="40"/>
    </form>