SDK for iOS Developer's Guide

Marker Clustering

You can use marker clustering to reduce the visual overload caused by too many markers being displayed on the map at once. With this feature markers that are close together are automatically replaced by numbered cluster markers to indicate that multiple map markers are represented. For better user experience, the replacement algorithm depends on the device pixel density. Therefore you can observe different behavior on different devices.

Figure 1. Cluster Markers

Showing Cluster Markers

You can enable cluster markers on a map by using an NMAClusterLayer and adding map markers to it. All markers that are on a layer are automatically clustered based on a grid-based clustering algorithm that depends on the map zoom level.

The following steps demonstrate how to use NMAClusterLayer class:

  1. Create map markers as usual:
    NMAMapMarker *mm =
      [NMAMapMarker
        mapMarkerWithGeoCoordinates:[NMAGeoCoordinates geoCoordinatesWithLatitude:54.54
          longitude:13.23]
        image:[UIImage imageNamed:@"marker@1x.png"]];
    
  2. Create a ClusterLayer object.
    NMAClusterLayer *cl = [[NMAClusterLayer alloc] init];
  3. Add markers to the cluster layer instead of the map directly.
    [cl addMarker:mm];
    You can also add an NSArray of NMAMapMarker instead of just adding a single marker by using addMarkers: method.
  4. Add the cluster layer to the map.
    [activeMapView addClusterLayer:cl];
    Note: The order of these two steps is not important. You can also add the cluster layer to the map first and add markers to the cluster layer afterwards.
  5. To remove a marker or collection or markers from the cluster layer again, call:
    [cl removeMarker:mm];

You can also retrieve all markers on a cluster layer with markers property in NMAClusterLayer. This is useful in case if you would like to remove all markers by using removeMarkers: method.

Theming

You can customize clusters by assigning an NMAClusterTheme object to the NMAClusterLayer. Every theme consists of several styles, where a cluster style defines the look of marker cluster objects at a particular density. Cluster density is an indication of how many markers a cluster represents.

Figure 2. A Cluster with Density of 7

There are three available cluster styles that you can use with an NMAClusterTheme:

  • Default cluster style - the predefined markers behavior. This is the default style used if you do not set a theme. It is also used for ranges that are not covered by your own theme.
  • NMABasicClusterStyle - similar to the default style but you can change the fill color, text color, and stroke color for the markers.
  • NMAImageClusterStyle - use your own bitmap image as a marker.

To set a style, use setStyle:forDensityRange: method in NMAClusterTheme. For example, if you want red for all clusters between density 10 to 19, and green for 20 to 30, and the default blue for all other cases, you can use NMABasicClusterStyle as follows:

  1. Create a style with a red circle and a style with a green one:
    NMABasicClusterStyle *redStyle = [NMABasicClusterStyle style];
    redStyle.fillColor = [UIColor redColor];
    NMABasicClusterStyle *greenStyle = [NMABasicClusterStyle style];
    greenStyle.fillColor = [UIColor greenColor];
    
  2. Create a new theme and add those styles to the theme along with defining the density ranges they should be used for:
    NMAClusterTheme *theme = [[NMAClusterTheme alloc] init];
    [theme setStyle:redStyle forDensityRange:NSMakeRange(10, 9)];
    [theme setStyle:greenStyle forDensityRange:NSMakeRange(20, 10)];
    
    Note: Make sure that density ranges do not overlap, or otherwise setStyle:forDensityRange: returns NO.
  3. Finally, add this theme to the cluster layer you use:
    cl.theme = theme;

To use your own image as a cluster icon, set a UIImage to an NMAImageClusterStyle instance before setting the style to the cluster theme. For example:

NMAImageClusterStyle *imageStyle =
  [NMAImageClusterStyle
    styleWithUIImage:[UIImage imageNamed:@"cluster-icon.png"]];

NMAClusterTheme *theme = [[NMAClusterTheme alloc] init];
  [theme setStyle:imageStyle forDensityRange:NSMakeRange(2, 8)];
  cl.theme = theme;

Although you can only set one theme per layer, you can mix styles for different densities in a single theme. For example, you can set an NMABasicClusterStyle for density from 10 to 19 and an NMAImageClusterStyle from 20 to 30. The default theme applies for all other densities that are not covered by the custom themes.

Cluster Marker Events

Cluster markers are similar to normal markers on the map. You can also use map object gesture delegates in similar way as normal map markers. For example:

  1. Set an NMAMapView delegate:
    self.mapView.delegate = self;
  2. Implement mapView:didSelectObjects: to get the map click event.
    - (void)mapView:(NMAMapView *)mapView didSelectObjects:(NSArray *)objects
    {
      for (NMAClusterViewObject *object in objects) {
        if ([object isKindOfClass:[NMAClusterViewObject class]]) {
          NSLog(@"Cluster of %d markers", object.markers.count);
        }
      }
    }

Working with Clusters

HERE SDK also provides a few other ways for you to interact with marker clusters. You can get all markers inside one specific cluster by using NMAClusterViewObject, which is a proxy object class representing a cluster. For example:

NMAGeoCoordinates *coordinates =
  [NMAGeoCoordinates geoCoordinatesWithLatitude:0 longitude:0]; // Your coordinates
NSArray *objects =
  [self.mapView objectsAtPoint:[self.mapView pointFromGeoCoordinates:coordinates]];

for (NMAClusterViewObject *object in objects) {
    if ([object isKindOfClass:[NMAClusterViewObject class]]) {
      NSArray *clusterMarkers = object.markers; // Your clustered markers
    }
  }

You can also retrieve the bounding box around all markers that are in a cluster marker by calling the following:

NMAClusterViewObject *cluster;
NMAGeoBoundingBox *boundingBox = cluster.boundingBox;