Карта
Создание карты
Чтобы создать карту, нужно вызвать метод makeMapFactory() и передать настройки карты в виде структуры MapOptions.
В настройках важно указать корректное для устройства значение PPI. Его можно найти в спецификации устройства.
Кроме этого в настройках можно указать начальную позицию камеры, границы масштабирования и другие параметры.
// Настройки карты.
var mapOptions = MapOptions.default
// Значение PPI для устройства.
mapOptions.devicePPI = devicePPI
// Создание фабрики объектов карты.
let mapFactory: PlatformMapSDK.IMapFactory = sdk.makeMapFactory(options: mapOptions)
Получить слой карты можно через свойство mapView
. Контроллер карты доступен через свойство map
(см. класс Map).
// Слой карты.
let mapView: UIView & IMapView = mapFactory.mapView
// Контроллер карты.
let map = mapFactory.map
Добавление объектов
Для добавления динамических объектов на карту (маркеров, линий, кругов, многоугольников) нужно создать менеджер объектов (MapObjectManager), указав инстанс карты.
// Сохраняем объект в свойство, так как при удалении менеджера исчезают все связанные с ним объекты на карте.
self.objectManager = MapObjectManager(map: map)
Для добавления объектов используются методы addObject() и addObjects(). Для каждого динамического объекта можно указать поле userData
, которое будет хранить произвольные данные, связанные с объектом. Настройки объектов можно менять после их создания.
Для удаления объектов используются методы removeObject() и removeObjects(). Чтобы удалить все объекты, можно использовать метод removeAll().
Маркер
Чтобы добавить маркер на карту, нужно создать объект Marker, указав нужные настройки (MarkerOptions), и передать его в вызов addObject()
менеджера объектов.
Иконку для маркера можно создать с помощью метода make()
фабрики изображений (IImageFactory), используя UIImage, PNG-данные или SVG-разметку.
// Иконка на основе UIImage.
let uiImage = UIImage(systemName: "umbrella.fill")!.withTintColor(.systemRed)
let icon = sdk.imageFactory.make(image: uiImage)
// Иконка на основе SVG-данных.
let icon = sdk.imageFactory.make(svgData: imageData, size: imageSize)
// Иконка на основе PNG-данных (быстрее, чем из UIImage).
let icon = sdk.imageFactory.make(pngData: imageData, size: imageSize)
// Настройки маркера.
let options = MarkerOptions(
position: GeoPointWithElevation(
latitude: 55.752425,
longitude: 37.613983
),
icon: icon
)
// Создание и добавление маркера.
let marker = Marker(options: options)
objectManager.addObject(object: marker)
Чтобы изменить точку привязки иконки (выравнивание иконки относительно координат на карте), нужно указать параметр anchor.
Линия
Чтобы нарисовать на карте линию, нужно создать объект Polyline, указав нужные настройки, и передать его в вызов addObject()
менеджера объектов.
Кроме массива координат для точек линии, в настройках можно указать ширину линии, цвет, пунктир, обводку и другие параметры (см. PolylineOptions).
// Координаты вершин ломаной линии.
let points = [
GeoPoint(latitude: 55.7513, longitude: value: 37.6236),
GeoPoint(latitude: 55.7405, longitude: value: 37.6235),
GeoPoint(latitude: 55.7439, longitude: value: 37.6506)
]
// Настройки линии.
let options = PolylineOptions(
points: points,
width: LogicalPixel(value: 2),
color: DGis.Color.init()
)
// Создание и добавление линии.
let polyline = Polyline(options: options)
objectManager.addObject(object: polyline)
Многоугольник
Чтобы нарисовать на карте многоугольник, нужно создать объект Polygon, указав нужные настройки, и передать его в вызов addObject()
менеджера объектов.
Координаты для многоугольника указываются в виде двумерного массива. Первый вложенный массив должен содержать координаты основных вершин многоугольника. Остальные вложенные массивы не обязательны и могут быть заданы для того, чтобы создать вырез внутри многоугольника (один дополнительный массив - один вырез в виде многоугольника).
Дополнительно можно указать цвет полигона и параметры обводки (см. PolygonOptions).
// Настройки многоугольника.
let options = PolygonOptions(
contours: [
// Вершины многоугольника.
[
GeoPoint(latitude: 55.72014932919687, longitude: 37.562599182128906),
GeoPoint(latitude: 55.72014932919687, longitude: 37.67555236816406),
GeoPoint(latitude: 55.78004852149085, longitude: 37.67555236816406),
GeoPoint(latitude: 55.78004852149085, longitude: 37.562599182128906),
GeoPoint(latitude: 55.72014932919687, longitude: 37.562599182128906)
],
// Координаты выреза внутри многоугольника.
[
GeoPoint(latitude: 55.754167897761, longitude: 37.62422561645508),
GeoPoint(latitude: 55.74450654680055, longitude: 37.61238098144531),
GeoPoint(latitude: 55.74460317215391, longitude: 37.63435363769531),
GeoPoint(latitude: 55.754167897761, longitude: 37.62422561645508)
]
],
color: DGis.Color.init(),
strokeWidth: LogicalPixel(value: 2)
)
// Создание и добавление многоугольника.
let polygon = Polygon(options: options)
objectManager.addObject(object: polygon)
Кластеризация
Для добавления маркеров на карту в режиме кластеризации нужно создать менеджер объектов (MapObjectManager) через MapObjectManager.withClustering(), указав инстанс карты, расстояние между кластерами в логических пикселях, максимальный zoom-уровень формирования кластеров и пользовательскую имплементацию протокола SimpleClusterRenderer. SimpleClusterRenderer используется для кастомизации кластеров в MapObjectManager.
final class SimpleClusterRendererImpl: SimpleClusterRenderer {
private let image: DGis.Image
private var idx = 0
init(
image: DGis.Image
) {
self.image = image
}
func renderCluster(cluster: SimpleClusterObject) -> SimpleClusterOptions {
let textStyle = TextStyle(
fontSize: LogicalPixel(15.0),
textPlacement: TextPlacement.rightTop
)
let objectCount = cluster.objectCount
let iconMapDirection = objectCount < 5 ? MapDirection(value: 45.0) : nil
idx += 1
return SimpleClusterOptions(
icon: self.image,
iconMapDirection: iconMapDirection,
text: String(objectCount),
textStyle: textStyle,
iconWidth: LogicalPixel(30.0),
userData: idx,
zIndex: ZIndex(value: 6),
animatedAppearance: false
)
}
}
self.objectManager = MapObjectManager.withClustering(
map: map,
logicalPixel: LogicalPixel(80.0),
maxZoom: Zoom(19.0),
clusterRenderer: SimpleClusterRendererImpl(image: self.icon)
)
Управление камерой
Для работы с камерой используется объект Camera, доступный через свойство map.camera
.
Перелёт
Чтобы запустить анимацию перелёта камеры, нужно вызвать метод move() и указать параметры перелёта:
position
- конечная позиция камеры (координаты и уровень приближения). Дополнительно можно указать наклон и поворот камеры (см. CameraPosition).time
- продолжительность перелёта в секундах (TimeInterval).animationType
- тип анимации (CameraAnimationType).
Функция move()
возвращает объект Future, который можно использовать, чтобы обработать событие завершения перелета.
// Новая позиция камеры.
let newCameraPosition = CameraPosition(
point: GeoPoint(latitude: 55.752425, longitude: 37.613983),
zoom: Zoom(value: 16)
)
// Запуск перелёта.
let future = map.camera.move(
position: newCameraPosition,
time: 0.4,
animationType: .linear
)
// Получение события завершения перелета.
let cancellable = future.sink { _ in
print("Перелет камеры завершён.")
} failure: { error in
print("Возникла ошибка: \(error.localizedDescription)")
}
Получение состояния камеры
Текущее состояние камеры (находится ли камера в полёте) можно получить, используя свойство state
. См. CameraState для списка возможных состояний камеры.
let currentState = map.camera.state
Подписаться на изменения состояния камеры можно, используя stateChannel.sink
.
// Подписка.
let connection = map.camera.stateChannel.sink { state in
print("Состояние камеры изменилось на \(state)")
}
// Отписка.
connection.cancel()
Получение позиции камеры
Текущую позицию камеры можно получить, используя свойство position
(см. структуру CameraPosition).
let currentPosition = map.camera.position
print("Координаты: \(currentPosition.point)")
print("Приближение: \(currentPosition.zoom)")
print("Наклон: \(currentPosition.tilt)")
print("Поворот: \(currentPosition.bearing)")
Подписаться на изменения позиции камеры (и угла наклона/поворота) можно, используя positionChannel.sink
.
// Подписка.
let connection = map.camera.positionChannel.sink { position in
print("Изменилась позиция камеры или угол наклона/поворота.")
}
// Отписка.
connection.cancel()
Моё местоположение
На карту можно добавить специальный маркер, который будет отражать текущее местоположение устройства. Для этого нужно создать источник данных MyLocationMapObjectSource() и указав контейнер объектов SDK (sdk.context
). Созданный источник нужно передать в метод карты addSource().
// Создание источника данных.
let source = MyLocationMapObjectSource(
context: sdk.context,
directionBehaviour: MyLocationDirectionBehaviour.followMagneticHeading
)
// Добавление маркера на карту.
map.addSource(source: source)
Чтобы удалить маркер, нужно вызвать метод removeSource(). Список активных источников данных можно получить, используя свойство map.sources
.
map.removeSource(source)
Слой пробок
Для отображения слоя пробок необходимо создать TrafficSource и передать его в метод карты addSource().
let trafficSource = TrafficSource(context: sdk.context)
map.addSource(source: trafficSource)
Получение объектов по экранным координатам
Информацию об объектах на карте можно получить, используя пиксельные координаты. Для этого нужно вызвать метод карты getRenderedObjects(), указав координаты в пикселях и радиус в экранных миллиметрах. Метод вернет отложенный результат, содержащий информацию обо всех найденных объектах в указанном радиусе на видимой области карты (массив RenderedObjectInfo).
Пример функции, которая принимает координаты нажатия на экран и передает их в метод getRenderedObjects()
:
private func tap(location: CGPoint) {
let scale = UIScreen.main.nativeScale
let point = ScreenPoint(x: Float(location.x * scale), y: Float(location.y * scale))
self.getRenderedObjectsCancellable?.cancel()
let cancel = map.getRenderedObjects(centerPoint: point).sink(
receiveValue: {
infos in
// Первый объект в массиве - самый близкий к координатам.
guard let info = infos.first else { return }
// Обработка результата в главной очереди.
DispatchQueue.main.async {
[weak self] in
self?.handle(selectedObject: info)
}
},
failure: { error in
print("Ошибка получения информации об объектах: \(error)")
}
)
// Сохраняем результат вызова, так как его удаление отменяет обработку.
self.getRenderedObjectsCancellable = cancel
}
Распознаватель жестов карты
Для кастомизации распознавателя жестов карты, необходимо задать реализацию протокола IMapGestureView в IMapView или реализацию IMapGestureViewFactory в MapOptions. Если ни одна из этих имплементаций задана не будет, то будет использована реализация по умолчанию. Пример такой кастомизации распознавателя можно посмотреть здесь.