Кластеризация маркеров

Выберите платформу: Android iOS JavaScript

На этой странице описана утилита для кластеризации маркеров, доступная в библиотеке утилит для Maps SDK для iOS.

Кластеризация маркеров позволяет добавить на карту много маркеров и сделать так, чтобы все ее данные легко читались. Библиотека кластеризации маркеров помогает управлять несколькими маркерами на разных уровнях масштабирования.

Когда пользователь просматривает карту в большом масштабе, на ней отображаются отдельные маркеры. При уменьшении масштаба маркеры собираются в кластеры, что упрощает чтение карты.

На снимке экрана показан стандартный стиль для кластера маркеров.

Карта с кластеризованными маркерами в стандартном стиле

Ниже – пример настраиваемого кластера маркеров:

Карта с настраиваемой кластеризацией маркеров

Требования и примечания

Библиотека утилит Maps SDK для iOS

Утилита для кластеризации маркеров входит в состав библиотеки утилит Maps SDK для iOS. Если вы ещё не настроили эту библиотеку, выполните рекомендации из руководства по настройке, прежде чем продолжить чтение этой страницы.

С целью обеспечения наилучшей производительности рекомендуется, чтобы количество маркеров не превышало 10 000.

Доступ к данным о местоположении

В этом примере для определения местоположения пользователя и карты по его координатам используется GPS устройства. Для этого добавьте описание разрешения NSLocationWhenInUseUsageDescription в файл Info.plist проекта.

Чтобы добавить его, выполните следующие действия:

  1. В навигаторе проектов Xcode нажмите на файл Info.plist, чтобы открыть редактор списка свойств.
  2. Нажмите на значок плюса рядом с пунктом Information Property List (Список свойств информации), чтобы добавить новое свойство.
  3. В поле key введите NSLocationWhenInUseUsageDescription. Xcode автоматически преобразует его в полное название Privacy – Location When In Use Usage Description. Полный список возможных свойств разрешений на доступ к данным о местоположении можно найти в статье Запрос авторизации для сервисов геолокации в документации для разработчиков Apple.
  4. В поле "Тип" оставьте значение "Строка".
  5. В поле "Значение" укажите, почему вашему приложению требуется доступ к данным о местоположении пользователя. Например: "Определяет местоположение пользователя, чтобы показывать ему компании поблизости".

Как реализовать кластеризацию маркеров

Чтобы реализовать кластеризацию маркеров, выполните следующие действия:

  1. Создайте экземпляр ClusterManager.
  2. Передайте маркеры, которые нужно объединить в кластеры, в менеджер кластеров.
  3. Вызовите менеджер кластеров.
Полный пример реализации кластеризации маркеров можно посмотреть в примерах приложений на Objective-C и Swift на GitHub.

Создание менеджера кластера

Чтобы использовать менеджер кластеров, выполните следующие действия:

  1. Настройте ViewController, где отображается карта, в соответствии с протоколом GMSMapViewDelegate.
  2. Создайте экземпляр GMUClusterManager.
  3. Передайте экземпляр GMSMapView, в котором вы хотите реализовать кластеризацию маркеров, и реализации следующих протоколов в экземпляр GMUClusterManager:
    • GMUClusterIconGenerator: предоставляет логику приложения, которая извлекает значки кластеров для использования на разных уровнях масштабирования.
    • GMUClusterAlgorithm – определяет алгоритм, который задает поведение кластеризации маркеров, например расстояние между маркерами, которые нужно включить в один кластер.
    • GMUClusterRenderer – предоставляет логику приложения, которая обрабатывает фактическую отрисовку значков кластеров на карте.
  4. Задайте делегат карты в экземпляре GMUClusterManager.

В библиотеке утилит есть стандартные реализации генератора значков (GMUDefaultClusterIconGenerator), алгоритма (GMUNonHierarchicalDistanceBasedAlgorithm) и средства отрисовки (GMUDefaultClusterRenderer). При необходимости вы можете создать собственные версии этих компонентов.

В следующем коде создается менеджер кластеров с использованием этих значений по умолчанию в обратном вызове viewDidLoad для ViewController:

Swift

import GoogleMaps
import GoogleMapsUtils

class MarkerClustering: UIViewController, GMSMapViewDelegate {
  private var mapView: GMSMapView!
  private var clusterManager: GMUClusterManager!

  override func viewDidLoad() {
    super.viewDidLoad()

    // Set up the cluster manager with the supplied icon generator and
    // renderer.
    let iconGenerator = GMUDefaultClusterIconGenerator()
    let algorithm = GMUNonHierarchicalDistanceBasedAlgorithm()
    let renderer = GMUDefaultClusterRenderer(mapView: mapView,
                                clusterIconGenerator: iconGenerator)
    clusterManager = GMUClusterManager(map: mapView, algorithm: algorithm,
                                                      renderer: renderer)

    // Register self to listen to GMSMapViewDelegate events.
    clusterManager.setMapDelegate(self)
    // ...
  }
  // ...
}
      

Objective-C

@import GoogleMaps;
@import GoogleMapsUtils;

@interface MarkerClustering () <GMSMapViewDelegate>

@end

@implementation MarkerClustering {
  GMSMapView *_mapView;
  GMUClusterManager *_clusterManager;
}

- (void)viewDidLoad {
  [super viewDidLoad];

  // Set up the cluster manager with a supplied icon generator and renderer.
  id<GMUClusterAlgorithm> algorithm =
      [[GMUNonHierarchicalDistanceBasedAlgorithm alloc] init];
  id<GMUClusterIconGenerator> iconGenerator =
      [[GMUDefaultClusterIconGenerator alloc] init];
  id<GMUClusterRenderer> renderer =
      [[GMUDefaultClusterRenderer alloc] initWithMapView:_mapView
                                    clusterIconGenerator:iconGenerator];
  _clusterManager =
      [[GMUClusterManager alloc] initWithMap:_mapView
                                   algorithm:algorithm
                                    renderer:renderer];

  // Register self to listen to GMSMapViewDelegate events.
  [_clusterManager setMapDelegate:self];
  // ...
}
// ...
@end
      

Добавление маркеров

Добавить маркеры в библиотеку кластеризации маркеров можно двумя способами: по отдельности или в виде массива.

Отдельный маркер

Swift

let position = CLLocationCoordinate2D(latitude: 47.60, longitude: -122.33)
let marker = GMSMarker(position: position)
clusterManager.add(marker)
      

Objective-C

CLLocationCoordinate2D position = CLLocationCoordinate2DMake(47.60, -122.33);
GMSMarker *marker = [GMSMarker markerWithPosition:position];
[_clusterManager addItem:marker];
      

Массив маркеров

Swift

let position1 = CLLocationCoordinate2D(latitude: 47.60, longitude: -122.33)
let marker1 = GMSMarker(position: position1)

let position2 = CLLocationCoordinate2D(latitude: 47.60, longitude: -122.46)
let marker2 = GMSMarker(position: position2)

let position3 = CLLocationCoordinate2D(latitude: 47.30, longitude: -122.46)
let marker3 = GMSMarker(position: position3)

let position4 = CLLocationCoordinate2D(latitude: 47.20, longitude: -122.23)
let marker4 = GMSMarker(position: position4)

let markerArray = [marker1, marker2, marker3, marker4]
clusterManager.add(markerArray)
      

Objective-C

CLLocationCoordinate2D position1 = CLLocationCoordinate2DMake(47.60, -122.33);
GMSMarker *marker1 = [GMSMarker markerWithPosition:position1];

CLLocationCoordinate2D position2 = CLLocationCoordinate2DMake(47.60, -122.46);
GMSMarker *marker2 = [GMSMarker markerWithPosition:position2];

CLLocationCoordinate2D position3 = CLLocationCoordinate2DMake(47.30, -122.46);
GMSMarker *marker3 = [GMSMarker markerWithPosition:position3];

CLLocationCoordinate2D position4 = CLLocationCoordinate2DMake(47.20, -122.23);
GMSMarker *marker4 = [GMSMarker markerWithPosition:position4];

NSArray<GMSMarker *> *markerArray = @[marker1, marker2, marker3, marker4];
[_clusterManager addItems:markerArray];
      

Как вызвать библиотеку кластеризации маркеров

После того как вы создали библиотеку кластеризации маркеров и передали ей маркеры, которые нужно объединить в кластеры, вам нужно вызвать метод cluster в экземпляре библиотеки кластеризации маркеров.

Swift

clusterManager.cluster()
      

Objective-C

[_clusterManager cluster];
      

Обработка событий маркеров и кластеров

В Maps SDK для iOS, чтобы отслеживать события на карте, необходимо реализовать протокол GMSMapViewDelegate. Вы можете прослушивать события карты, но не события типобезопасного менеджера кластеров. Когда пользователь нажимает на маркер, отдельный элемент кластера или кластер, API активирует mapView:didTapMarker: и прикрепляет дополнительные данные кластера к свойству marker.userData. Затем вы можете проверить, соответствует ли userData протоколу GMUCluster, чтобы определить, на что нажал пользователь – на значок кластера или на маркер.

Swift

func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool {
  // center the map on tapped marker
  mapView.animate(toLocation: marker.position)
  // check if a cluster icon was tapped
  if marker.userData is GMUCluster {
    // zoom in on tapped cluster
    mapView.animate(toZoom: mapView.camera.zoom + 1)
    NSLog("Did tap cluster")
    return true
  }

  NSLog("Did tap a normal marker")
  return false
}
      

Objective-C

- (BOOL)mapView:(GMSMapView *)mapView didTapMarker:(GMSMarker *)marker {
  // center the map on tapped marker
    [_mapView animateToLocation:marker.position];
    // check if a cluster icon was tapped
    if ([marker.userData conformsToProtocol:@protocol(GMUCluster)]) {
      // zoom in on tapped cluster
      [_mapView animateToZoom:_mapView.camera.zoom + 1];
      NSLog(@"Did tap cluster");
      return YES;
    }

    NSLog(@"Did tap marker in cluster");
    return NO;
}
      

Менеджер кластеров теперь перехватывает все события, которые вы реализовали в clusterManager. Остальные события перенаправляются делегату карты, если он указан. Обратите внимание, что события для стандартных маркеров (т. е. маркеров, не созданных средством визуализации кластеров) всегда перенаправляются делегату карты.

Как настроить кластеризацию маркеров

Вы можете создать собственную реализацию для GMUClusterRenderer, GMUClusterIconGenerator или GMUClusterAlgorithm. Вы можете создать собственную реализацию на основе примеров, включенных в библиотеку утилит, или написать полностью собственный код, соответствующий протоколам.