Flea777
Flea777

Reputation: 1022

HERE Maps JS API v3 cluster provider hangs adding many DataPoints

I'm messing with the migration of HERE Maps JS API from v2.5.4 to v3.

The biggest issue I'm facing is related to the H.clustering.Provider. While the v2.x version worked like a charm, the v3 version seems to be really slow.

Given the following code:

var clusterProvider = new H.clustering.Provider([], {
    clusteringOptions: {
        eps: 32,
        minWeight: 3,
        max: 20,
        min: 10
    }
});

var clusteringLayer = new H.map.layer.ObjectLayer(clusterProvider);

map.addLayer(clusteringLayer);

for(i = 0; i < 1000; i++)
{
    var lat = 43 + (i * 0.001);
    var lng = 13 + (i * 0.001);
    var dp = new H.clustering.DataPoint(lat, lng, null, null);
    clusterProvider.addDataPoint(dp); // <- this line cause hanging
}

The page hangs for many seconds before rendering the cluster.

In the documentation, I read:

addDataPoint (dataPoint)

This method adds a data point to the provider. Beware that this method provokes reclustering of the whole data set.

However, I cannot use the setDataPoints method because I need the cluster to refresh at every map pan or zoom (and not to start over).

In the v2 version I would have called the addObject method of the clustering provider for each data point and the cluster at the end. This workflow was immediate.

Any idea?

Thanks in advance

Upvotes: 1

Views: 799

Answers (1)

echom
echom

Reputation: 932

So, from what I get from the documentation and the example here, I think your issue is that for every point you add you're running a full re-clustering of the entire data set (whatever you have already added). So you will have 1000 clustering operations becoming more and more complex as you add individual data points.

In your case, you should be fine either filling the data points array before instantiating the Provider or using setDataPoints at a later stage. The clustering operation has to happen at some point. In the old API it would happen when you call 'cluster' but now it happens on demand when the object layer is rendered and every time you either add data points or set the data points.

The map already takes care of updating the markers for you based on the static cluster calculation.

In summary the process is as follows:

  1. The provider receives an array of data points as data set
  2. It clusters this data set globally and produces a static clustering result for all zoom levels
  3. When the map renders the theme is invoked for each cluster and noise point in the already-computed clustering result in order to render the proper markers for the current map position and zoom level
  4. Repeat 1-3 whenever the data set changes

So give the example linked above a spin (it clusters more than a thousand points with hardly any delay for me) and see if it does what you're looking for.

EDIT: (based on comments below) Here are my suggestions: Keep two arrays, one representing your whole data set, one keeping track of change batches. Always populate the batch array from your server responses. Once mapviewchangeend hits add the batch array to the data array and then set the data set array on the provider.

var clusterProvider = new H.clustering.Provider([], {
    clusteringOptions: {
        eps: 32,
        minWeight: 3,
        max: 20,
        min: 10
    }
});
var clusteringLayer = new H.map.layer.ObjectLayer(clusterProvider);
map.addLayer(clusteringLayer);


var clusterSet = [],
    batchSet = [],
    maxDataSetSize = 5000;

map.addEventListener('mapviewchangeend', function() {
  // if we added any points between mapviewchangestart / end
  if(batchSet.length > 0) {
    // we add the data and slice take a subset of 5000 points to keep
    // the data set at manageable size (adjust to your liking)
    clusterSet = batchSet.concat(clusterSet).slice(0, maxDataSetSize);
    clusteringProvider.setDataPoints(clusterSet);
  }
  batchSet = [];
});

//whereever you receive your data:
function onReceiveData(dataPoints) {
  // always push to the batch set
  batchSet = batchSet.concat(dataPoints);
}

Upvotes: 2

Related Questions