# Display your assets on Woosmap Map using Marker Clustering

**URL:** <https://forum.woosmap.com/t/display-your-assets-on-woosmap-map-using-marker-clustering/125>\
**Category:** Guides\
**Tags:** map-api\
**Created:** [September 20, 2022, 10:22am UTC](https://forum.woosmap.com/t/display-your-assets-on-woosmap-map-using-marker-clustering/125 "2022-09-20T10:22:19Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![gael](https://dub1.discourse-cdn.com/flex013/user_avatar/forum.woosmap.com/gael/32/3_2.png) [@gael](https://forum.woosmap.com/u/gael)\
**Post date:** [September 20, 2022, 10:22am UTC](https://forum.woosmap.com/t/display-your-assets-on-woosmap-map-using-marker-clustering/125/1 "2022-09-20T10:22:19Z")

</div>

> **Now in the documentation.** This technique ships as two runnable samples: [Map Clustering with GeoJSON](https://developers.woosmap.com/js-samples/map-clustering-geojson/) for the case below, and [Map Clustering with Stores](https://developers.woosmap.com/js-samples/map-clustering-stores/) for assets hosted in your own Woosmap project.

Displaying a large number of points on a map, keeping it clear and usable is a hard job, especially at higher level where identifying each feature is quite impossible.

Marker clustering is a technique where individual points are grouped into clusters according to a specific algorithm based on the radius of clusters. Grouped points are represented on the map by a marker, the cluster symbol, with the number of points included in it. Clustering eliminates overlapping points and makes the web map clearer.

Here is an image that shows how your web mapping application will look like implementing this representation method.

 ![clustering|](https://europe1.discourse-cdn.com/flex013/uploads/woosmap/original/1X/e261423376b66ac53771bef0696521004a075b84.jpeg)

When zooming in, the clusters shrink, and individual points are displayed when distance exceed radius parameter.

Check this live example which displays all the pubs across the UK ~ 22.000 pubs 🍺:

https://codesandbox.io/embed/supercluster-woosmapmap-pubs-u3zu0x?hidedevtools=1&hidenavigation=1&theme=light&view=preview

This sample implements the popular [Supercluster](https://www.npmjs.com/package/supercluster) library which uses the [k-d trees](https://en.wikipedia.org/wiki/K-d_tree) data structure for spatial indexing. Having an index for each zoom allows to instantly query clusters for any map view and ensure smooth transitions between zoom levels.

Supercluster works pretty well for Woosmap Map JS. The library expect location data to be in the form of an array of [GeoJSON Feature](https://tools.ietf.org/html/rfc7946#section-3.2) objects. Each feature’s `geometry` must be a [GeoJSON Point](https://tools.ietf.org/html/rfc7946#section-3.1.2).

First step is to load your GeoJSON file and build the spatial index as below:

```javascript
fetch("https://demo.woosmap.com/misc/data/uk-all-pubs.geojson")
    .then((response) => response.json())
    .then((data) => {
      const geojsonFeatures = data["features"];
      index = new Supercluster({
        radius: 40,
        extent: 256,
        maxZoom: 14,
        minPoints: 5
      }).load(geojsonFeatures);
    });

```

Processing points is done only once. Clusters are computed for each zoom (between `minZoom` and `maxZoom` parameters).

To highlight processing time, you can pass `log: true` parameter to Supercluster constructor. For this sample, whole index is built in less than 50ms. Blazing fast!

```auto
prepare 22169 points: 1.5ms 
z14: 19530 clusters in 18ms
z13: 16822 clusters in 10ms
z12: 14141 clusters in 6ms
z11: 11050 clusters in 4ms
z10: 7121 clusters in 3ms
z9: 3101 clusters in 2ms
z8: 1020 clusters in 0ms
z7: 277 clusters in 0ms
z6: 86 clusters in 0ms
z5: 27 clusters in 0ms
z4: 9 clusters in 0ms
z3: 2 clusters in 0ms
z2: 1 clusters in 0ms
z1: 1 clusters in 0ms
z0: 1 clusters in 0ms
total time: 44.5ms 

```

Once built, clusters’ index can be displayed as a marker, labeled with the number of locations. Here the marker is a circle which radius and color vary depending on the cluster size.

```javascript
const clusterData = index.getClusters(bbox, map.getZoom());
const markers = clusterData.map((feature) => {
  return createClusterIcon(feature)
});
function createClusterIcon(feature) {
    const count = feature.properties.point_count;
    const color = count < 80 ? "#0B9D58" : count < 500 ? "#F5B300" : "#DA0A40";
    const size = count < 80 ? 45 : count < 400 ? 55 : 65;
    const svg = window.btoa(`
        <svg fill="${color}" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 240 240">
          <circle cx="120" cy="120" opacity=".2" r="110" />
        </svg>`);
    const marker = new woosmap.map.Marker({
        labelOrigin: new woosmap.map.Point(13, 15),
        label: {
            text: feature.properties.point_count_abbreviated,
            color: "white"
        },
        position: latlng,
        icon: {
            url: `data:image/svg+xml;base64,${svg}`,
            scaledSize: new window.woosmap.map.Size(size, size)
        },
        map: map
    });
    return marker;
}

```

* * *

We’re looking forward to seeing cool clustering implementation with Woosmap Map from you! If you have any questions or comments don’t hesitate to react in this thread.

---

<div class="post-metadata">

**Author:** ![gael](https://dub1.discourse-cdn.com/flex013/user_avatar/forum.woosmap.com/gael/32/3_2.png) [@gael](https://forum.woosmap.com/u/gael)\
**Post date:** [November 9, 2023, 4:15pm UTC](https://forum.woosmap.com/t/display-your-assets-on-woosmap-map-using-marker-clustering/125/2 "2023-11-09T16:15:55Z")

</div>

The above demo displays assets from a static GeoJSON file.  
Of course, you can also use the ones hosted in your Woosmap project.

You’ll first need to retrieve all assets before passing them to Supercluster library.

Since the Woosmap Search API limits the number of assets fetched at one time, you need to call the API repeatedly to get all your stores. Each search request is limited to 300 assets as a maximum.

Here is a sample which implements recursive Promises in Javascript. Calls to Woosmap Search are done through Woosmap Map JS class [`woosmap.map.StoresService`](https://developers.woosmap.com/products/map-api/reference/1.4/#woosmap.map.stores.StoresService).

```javascript
const storesService = new woosmap.map.StoresService();

const getAllStores = async () => {
    const allStores = [];
    const query = { storesByPage: 300 };
    
    const getStores = async (storePage) => {
      if (storePage) {
        query.page = storePage;
      }
      return storesService
        .search(query)
        .then((response) => {
          allStores.push(...response.features);
          if (query.page === response.pagination.pageCount) {
            return allStores;
          }
          return getStores(response.pagination.page + 1);
        })
        .catch((err) => {
          console.error(err);
          throw new Error("Error getting all stores");
        });
    };
    return getStores();
  };

  getAllStores().then((stores) => {
    index = new Supercluster({/*options*/}).load(stores);
  });

```

Details of the above code:

1. Define the asynchronous function **getAllStores()** to fetch all the assets from Woosmap
2. Define the asynchronous function, **getStores()**, to run the actual query on your project. It takes `storePage ` as a parameter. This is the function that will be called recursively.
3. Set the starting page number for the `query.page` based on the `storePage` and `query.storesByPage` to the max allowed number 300.
4. Call the StoresService **search** function. This function returns a Javascript Promise.
5. Add the fetched assets features to the **allStores** list.
6. When all assets have been fetched (i.e `storePage` is equal to `response.pagination.pageCount`) resolve the Promise with **allStores** list as the value.
7. As long as there are more assets to fetch, recursively call the **getStores()** function with the `storePage` as the input parameter.

The features returned from Woosmap Search API follow the GeoJSON standard so you can pass directly the results of **getAllStores** as a parameter to `SuperCluster.load()`.

See full demo here:

https://codesandbox.io/embed/supercluster-woosmapmap-stores-dsp9r6?hidedevtools=1&hidenavigation=1&theme=light&view=preview
