7

I am using the open layers 3 with supercluster at the moment, extending the example provided here : https://jsfiddle.net/d5gwvz2y/2/

My question is: How does one fetch all the underlying features behind a cluster if clicked? In open layers cluster implementation you could use cluster forEachFeature, or just getFeatures.

Here is a sample of the clusters working using default cluster implementation http://www.wwarn.org/surveyor/NMFI/ when a cluster is clicked, an array of features are returned, which can then be iterated through.

4
+100

I had to make some changes to the fiddle to get it running. What I changed:

  1. Use latest version of Supercluster (2.3.0) because it has a new function called getLeaves that you need (see 3.).
  2. Create a FeatureCollection (to have the advantage of identifying features by properties - e.g. name) and load it with supercluster:
var count = 200000;

// create featurecollection
var featureCollection = {
  "type": "FeatureCollection",
  "features": []
};

// add features to featurecollection
for (var i = 0; i < count; ++i) {
    var feature = {
    "type": "Feature",
    "properties": {
      "name": "point_"+i
    },
        "geometry": {
            "type": "Point",
            "coordinates": [(Math.random() * (-78.31801021112759 + 74.65681636347132) - 74.65681636347132).toFixed(10), (Math.random() * (37.92771687103033 - 39.366988155008926) + 39.366988155008926).toFixed(10)]
        }
    };
    featureCollection.features.push(feature);
}

// create supercluster
var index = supercluster({
    radius: 100,
    maxZoom: 16
});
index.load(featureCollection.features);
  1. Use getLeaves(clusterId, clusterZoom, limit = 10, offset = 0) in your select event (as described in the supercluster project):
selectSingleClick.on('select', function (selectEvent) {
  // get selected feature
  var feature = selectEvent.selected[0];
  // get parameter to call getLeaves
  var zoom = map.getView().getZoom();
  var clusterId = feature.get("cluster_id");
  // get features in cluster
  var featuresInCluster = index.getLeaves(clusterId, zoom, Infinity, 0);

  // iterate over features (NO ol.Feature objects!)
  for(let clusterObj of featuresInCluster){
    // do stuff with your feature!
  }
});

Have a look at this working JSFiddle.

EDIT: I updated the JSFiddle to fit the question requirements of looping through the resulting child elements...

Note that you do not access features in the cluster as ol.Feature objects because the access is realized with supercluster not openlayers! If necessary you could access the features in openlayers by searching for certain properties to identify the feature (e.g. name property in the provided JSFiddle).

  • 1
    Crossposted our answers :) . Yours is more complete with a working example for the particular use case, so this deserves to be put above mine for sure. – Senshi Apr 14 '17 at 16:04
3

It depends on what supercluster you are using. I assume it's the Mapbox supercluster, which lucky for you has implemented the method getLeaves() on 2017 Jan 18.

The method was implemented in particular for the purpose you are looking for ( you were not the first ask :-) ), and it was implemented with flexibility in mind as well (pagination).

The pull request also shows an in-detail explanation of the parameters of this function, I just copy them here for reference:

index.getLeaves(
    clusterId, // cluster_id property of the clicked cluster
    zoom,      // zoom of the clicked cluster
    limit,     // how many points to return; 10 by default
    offset);   // how many points to skip for pagination; 0 by default

If you want to get all points in a cluster, either set limit to Infinity(yes, that's a valid value!), or use a negative value such as -1.

If you try to retrieve large amount of point data (e.g. all 200k points in the example), you probably will have severe performance issues, plus you cannot sensibly display that information at once, either. Given your other example (showing details about a study represented by a point), you could use the additional parameters (limit, offset) to only request data as needed: Click on the cluster to open the popup/information, but only request a chunk of the data (e.g. the first ten studies), with the first being shown right away. Then, only when the user selects one of the other studies, do another request for the next chunk of studies. Not necessarily relevant to this question, but a quick introduction to pagination never hurts for stackexchange readers ;) : It's a great way to boost UX, with better performance allowing for sleeker ways to present data.

The relevant&merged pull request (My reputation limits me to only two links, so I had to "break" the link. Just add https:// in front):
github.com/mapbox/supercluster/pull/32

And if you want the background story of the pull request as well:
github.com/mapbox/mapbox-gl-js/issues/3318

  • Many thanks for the background and details of getLeaves, I'd share the bounty with you, if it was easily possible. Both answers were good, Lars with the working example had the edge this time. – Nigel_V_Thomas Apr 15 '17 at 11:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.