Map interaction

Maps are a key entity in the MapKit SDK. Users can navigate maps with special gestures.

This section describes the MapKit SDK's main features for implementing map interactions.

Coordinates

MapKit SDK uses two coordinate systems:

  • World: The real-world position of a point represented by the MMKPoint class. Points are defined by geographic coordinates, with latitude ranging from -90 to 90 and longitude ranging from -180 to 180.

  • Screen: The screen coordinate system represented by the MMKScreenPoint class. Sets a point relative to the screen size of the device in pixels. The coordinates range from the upper-left (0, 0) to the lower-right corner of the screen (MMKMapWindow.width(), MMKMapWindow.height()).

Here's how you can convert coordinates from one system to another:

Adding a map placemark positioned in the center of the screen:

let centerX = Float(mapView.mapWindow.width()) / 2.0
let centerY = Float(mapView.mapWindow.height()) / 2.0
let centerPoint = MMKScreenPoint(x: centerX, y: centerY)
// For example, worldPoint = (25.1982, 55.272758)
let worldPoint = mapView.mapWindow.screenToWorld(with: centerPoint) ?? MMKPoint()
let placemark = map.mapObjects.addPlacemark()
placemark.geometry = worldPoint
placemark.setIconWith(UIImage(named: "placemark_icon")!)

The code snippet above displays a placemark in the center of the map UI component.

Camera

You can move, rotate, tilt, and zoom the MapKit SDK camera with screen gestures or programmatically. That is handled by the camera, a separate entity that controls how the map is displayed on the user's device.

Camera position

The camera position is represented by the MMKCameraPosition class. To get the current camera position, use MMKMap.cameraPosition.

Here are the parameters that define the camera position.

Target

Map position. Displays the location that corresponds to the coordinates of the screen focus point.

Zoom

Map zoom level. The higher the zoom value, the more detailed the map's base level becomes. At the MMKCameraBounds.getMaxZoom() zoom level, the map is displayed at maximum zoom, while you can see the entire world map at the MMKCameraBounds.getMinZoom() zoom level.

Azimuth

Camera direction. The camera angle relative to north as measured in degrees, which is responsible for camera rotation. As you increase the azimuth value, the map rotates counterclockwise. The azimuth ranges from 0 to 360 degrees.

Tilt

Camera tilt value. Determines the angle between the camera and the map's surface. A tilt value of 0 results in a top-down perspective, while higher values increase the angle at which the map is displayed.

Camera movement

To move the camera, call the MMKMap.move(with:animation:cameraCallback:) method, which applies a new position value to it.

let cameraCallback: MMKMapCameraCallback = { isFinished in
    // Handle camera movement completion
}

map.move(
    with: MMKCameraPosition(
        target: MMKPoint(latitude: 25.1982, longitude: 55.272758),
        zoom: 13.0,
        azimuth: .zero,
        tilt: .zero
    ),
    animation: MMKAnimation(type: .linear, duration: 1.0),
    cameraCallback: cameraCallback
)

Use the MMKAnimation object to set the camera movement animation as well as its type and duration. The last parameter, MMKMapCameraCallback, is optional. You can use it to subscribe to camera movement completion events.

Focusing the camera on an object

One common camera movement scenario is focusing on an object.

Focusing the camera on a separate placemark is easy. To do so, use the camera movement method and pass the placemark position as an argument.

If the object you want to focus on is an area of the map, use the MMKMap.cameraPosition(with:azimuth:tilt:focus:) method. It takes the object geometry as the input and returns a MMKCameraPosition value. Once the camera finishes moving to that position, it automatically focuses on the object, working around the map viewport boundaries.

With MMKMap.cameraPosition(with:azimuth:tilt:focus:), you can get a new camera position (for example, to focus on a polyline object) and move the camera to it.

let geometry = MMKGeometry(polyline: polyline)
let cameraPosition = map.cameraPosition(
    with: geometry,
    azimuth: nil,
    tilt: nil,
    focus: nil
)
map.move(with: cameraPosition)

In addition to object geometry, MMKMap.cameraPosition(with:azimuth:tilt:focus:) also takes camera position values to be applied during movement.

Focus rect

Many map apps have an additional custom UI displayed on top of the MapKit SDK map. In those cases, calculating the correct camera position such that it accounts for the covered areas of the map can be a challenge. MapKit SDK provides a tool that solves that problem.

Focus rect sets the map area used when calculating the camera position. To change its value, use MMKMapWindow.focusRect. The entire map area is used by default.

Using the focus rect logic to focus on an object's geometry:

In the first screenshot, the polyline object is partially covered by user UI elements: the map at the bottom and the zoom controls on the right. In the second example, the focus rect area was calculated based on the size of the UI elements.

Focus rect calculation code:

let bottomPadding = Float(bottomCard.height)
let rightPadding = Float(rightButtons.width)

mapView.mapWindow.focusRect = MMKScreenRect(
    topLeft: MMKScreenPoint(x: .zero, y: .zero),
    bottomRight: MMKScreenPoint(
        x: Float(mapView.mapWindow.width()) - rightPadding,
        y: Float(mapView.mapWindow.height()) - bottomPadding
    )
)

Focus point

Focus point is the screen point that serves as a reference for camera movement and calculating the camera position. For example, when you call the MMKMap.move(with:animation:cameraCallback:) method, the camera moves to the screen focus point. Use MMKMapWindow.focusPoint to change its value. If the point isn't set, the center of the current focus rect is used instead by default.

Map events

The MapKit SDK supports a wide range of map events, including tapping, a variety of gestures, and camera position changes.

Tapping

You can use the MMKMapInputListener interface to subscribe to map tap events.

final private class InputListener: NSObject, MMKMapInputListener {
    func onMapTap(with map: MMKMap, point: MMKPoint) {
        // Handle single tap
    }

    func onMapLongTap(with map: MMKMap, point: MMKPoint) {
        // Handle long tap
    }
}
let inputListener = InputListener()

map.addInputListener(with: inputListener)

There are two types of map tap events: regular and long. Both types provide information on the map and the coordinates where the user tapped.

Gestures

The map can recognize user gestures. Each camera position parameter can be changed with an associated gesture:

Map loading

You can subscribe to successful map load events using the MMKMapLoadedListener interface. Maps are considered loaded when all their current tiles are downloaded. In some cases, the map can take a while to load, perhaps if the user is continuously scrolling or doesn't have an internet connection.

Note

The map load event notification is only triggered once, when all visible tiles are loaded and displayed. To get new event notifications, resubscribe to the MMKMapLoadedListener interface.

Changing the camera position

To track the camera in real time, subscribe to camera position change events in the MMKMapCameraListener interface.

Map resizing

Use the MMKMapSizeChangedListener interface to subscribe to map resize events.

final private class SizeChangedListener: NSObject, MMKMapSizeChangedListener {
    func onMapWindowSizeChanged(with mapWindow: MMKMapWindow, newWidth: Int, newHeight: Int) {
        // Handle window size changed
    }
}

POI

POIs (points of interest) are special MapKit map points that indicate interesting locations, objects, or organizations. They can include stores, restaurants, museums, sights, parks, or any other locations that may be of interest to the user.

The MapKit SDK supports interaction with POIs.

POI taps

Use the MMKLayersGeoObjectTapListener interface to handle POI tap events.

final private class GeoObjectTapListener: NSObject, MMKLayersGeoObjectTapListener {
    func onObjectTap(with event: MMKGeoObjectTapEvent) -> Bool {
        // Handle geoobject tap event
    }
}

private var geoObjectTapListener: GeoObjectTapListener()
map.addTapListener(with: geoObjectTapListener)

The tap event handler method takes a MMKGeoObjectTapEvent object, which encapsulates information about the map object that was tapped.

POI selection

To select a POI on the map, use the MMKMap.selectGeoObject(withObjectId:layerId:) method. You can then deselect it using the MMKMap.deselectGeoObject() method.

Geo objects

You can access information about a geo-object by calling MMKGeoObjectTapEvent.geoObject.

The MMKGeoObject class is a MapKit SDK entity that provides information about map objects. A geo object can be an organization, a building, or a geographic object like a country, city, or sea.

MMKGeoObject contains a large number of methods, providing access to the following data: