Skip to main content

Interact with the map

|

The Maps SDK for C++ map view natively supports common touch events click and double-click for zooming. The table below outlines the available gestures and their default behaviors on the map.

GestureDescription
Tap / Left ClickTap the screen with one finger or left mouse click. This gesture does not have a predefined map action.
Double Tap / Double Left ClickTo zoom the map in by a fixed amount, tap the screen twice with one finger or left mouse click.
Long Press / Long Left ClickPress and hold one finger or left mouse click to the screen. This gesture does not have a predefined map action.
PanTo move the map, press and hold one finger or left mouse click to the screen, and move it in any direction. The map will keep moving with a little momentum after the finger was lifted or left mouse button was raised.
2 Finger Pan / ShoveTo tilt the map, press and hold two fingers to the screen, and move them vertically. No behavior is predefined for other directions.
2 Finger TapTo align map towards north, tap the screen with two fingers.
PinchTo zoom in or out continuously, press and hold two fingers to the screen, and increase or decrease the distance between them. To rotate the map continuously, press and hold two fingers to the screen, and change the angle between them either by rotating them both or by moving one of them.
ScrollTo zoom in or out continuously, use the mouse scroll wheel in the desired direction.

The SDK provides support in MapView, for informing whenever the user performs and action that could be detected. Usually, you will want to add a specific behavior to your application after a gesture was detected, like performing a selection after a tap on map.

Event Handling in MapViewListener

MapViewListener derives from ICanvasListener, which provides a set of event methods for responding to user interactions on the map. Implement the following methods to handle each type of gesture:

  • Tap: onTouch
  • Double Tap (one finger taps the same area in quick succession): onDoubleTouch
  • Two Taps (two fingers tap the screen simultaneously): onTwoTouches
  • Long Press: onLongPress
  • Pan: onMove obtains the two points between which the movement occurred.
  • Shove: onShoveobtains the angle, and gesture specific points
  • Rotate: onMapAngleUpdate
  • Fling: onSwipe
  • Pinch: onPinch

The user can also listen for composite gestures:

  • Tap followed by a pan: onTouchMove
  • Pinch followed by a swipe: onPinchSwipe
  • Tap followed by a pinch: onTouchPinch
  • Two double touches: onTwoDoubleTouches
warning

Your implementation of MapViewListener can only be supplied when creating the MapView.

Use onViewRendered to retrieve information on the status updates of view data integrity and camera transitions whenever the map starts or stops moving.

warning

This callback is triggered when the camera is moved programmatically using methods like centerOnRoutes, followPosition, or centerOnArea, but not when the user performs a panning gesture. For detecting user behaviour, use onMove.

The onViewportResized method allows you to monitor when the map's viewport dimensions change. This can occur when the user resizes the application window or changes the orientation of the device. In this callback, you receive a RectType<int> object representing the new viewport size.

Use cases include:

  • Adjusting overlays or UI elements to fit the new viewport size.
  • Triggering animations or updates based on the map's dimensions.

Enable and disable gestures

Touch gestures can be disabled or enabled by calling enableTouchGestures method like so:

mapView->preferences().enableTouchGestures(ETouchGestures::TG_OnTouch, false);
Note

The desired gestures in the ETouchGestures enum list can be enabled or disabled by setting the enable parameter to true or false, respectively. By default, all gestures are enabled.

The TouchGestures enum supports the following gesture types:

  • Basic Touch: onTouch, onLongDown, onDoubleTouch, onTwoPointersTouch, onTwoPointersDoubleTouch
  • Movement: onMove, onTouchMove, onSwipe
  • Pinch and Rotation: onPinchSwipe, onPinch, onRotate, onShove
  • Combined Gestures: onTouchPinch, onTouchRotate, onTouchShove, onRotatingSwipe
  • Other: internalProcessing

For checking if a gesture is enables the isTouchGestureEnabled method can be used:

bool isTouchEnabled = mapView->preferences().isTouchGestureEnabled(ETouchGestures::TG_OnTouch);
warning

Executing resource-intensive tasks within MapViewListener related callbacks can degrade performance.

Map selection functionality

After detecting a gesture, such as a tap, usually some specific action like selecting a landmark or a route is performed on MapView. This selection is made using a map cursor, which is invisible by default. To showcase its functionality, the cursor can be made visible using the MapViewPreferences setting:

// Enable cursor (default is true)
mapView->preferences().enableCursor( true );
// Enable cursor to render on screen
mapView->preferences().enableCursorRender( true );

Doing this will result in a crosshair like icon in center of screen.

Displaying a cursor

Landmark selection

To get the selected landmarks, you can use the following code for example when a touch event is detected:


YourMapViewListenerImpl::onTouch(const Xy &pos)
{
// Set the cursor position.
mapView->setCursorScreenPosition(pos);

// Get the landmarks at the cursor position.
auto landmarks = mapView->cursorSelectionLandmarks();

for(const auto& landmark : landmarks)
{
// handle landmark
}
}
Note

At higher zoom levels, landmarks provided by the cursorSelectionLandmarks method may lack some details for optimization purposes. Use SearchService().searchLandmarkDetails to retrieve full landmark details if needed.

Note

The selected landmarks are returned by the cursorSelectionLandmarks function, which is called after updating the cursor's position. This step is essential because the SDK only detects landmarks that are positioned directly under the cursor.

warning

The cursor screen position is also used for determining the default screen position for centering (unless other values are specified). Modifying the screen position might change the behavior of centering in unexpected ways. Reset the cursor position to the center of the screen once you're done interacting with it.

Street selection

The following code can be used in order to return selected streets under the cursor:

YourMapViewListenerImpl::onTouch(const Xy &pos)
{
// Set the cursor position.
mapView->setCursorScreenPosition(pos);

// Get the streets at the cursor position.
auto streets = mapView->cursorSelectionStreets();

for(const auto& street : streets)
{
auto streetName = street.getName();
}
}
warning

Setting the cursor screen position is an asynchronous operation and each function call needs to be awaited. Otherwise, the result list may be empty. The operation is finished when the onViewRendered callback is received with tivStatus EViewDataTransitionStatus::VD_Complete.

Street name can then be displayed on screen. This is the result:

Displaying a cursor selected street name
Note

The visibility of the cursor has no impact whatsoever on the selection logic.

Getting the current cursor screen position is done by calling getCursorScreenPosition getter of MapView.

List of selection types

To summarize, there are multiple methods used to select different types of elements on the map. You can see all those in the following table.

EntitySelect methodResult typeObservations
LandmarkcursorSelectionLandmarksList<Landmark>
MarkercursorSelectionMarkersList<MarkerMatch>Returns MarkerMatch, not a Marker
OverlayItemcursorSelectionOverlayItemsList<OverlayItem>
StreetcursorSelectionStreetsList<Landmark>Streets are handled as landmarks
RoutecursorSelectionRoutesList<Route>
PathcursorSelectionPathPathEmpty is returned if no path is found
MapSceneObjectcursorSelectionMapSceneObjectMapSceneObjectEmpty is returned if no map scene object is found
TrafficEventcursorSelectionTrafficEventsList<TrafficEvent>

As you can see, when selecting markers a list of MarkerMatch elements is returned. The match specifies information about the matched marker (the marker collection in which the marker resides, the index of the marker in the collection, the matched part index, the matched index of the point in the part).

You can also override callbacks that are called when the cursor is placed over elements when implementing IMapViewListener class:

  • onCursorSelectionUpdatedLandmarks for landmarks
  • onCursorSelectionUpdatedMarkers for markers
  • onCursorSelectionUpdatedOverlayItems for overlay items
  • onCursorSelectionUpdatedRoutes for routes
  • onCursorSelectionUpdatedPath for paths
  • onCursorSelectionUpdatedTrafficEvents for traffic events
  • onCursorSelectionUpdatedMapSceneObject for map scene objects

These callbacks are triggered whenever the selection changes - for example, when new elements are selected, the selection switches to different elements, or the selection is cleared (in which case the callback is invoked with null or an empty list).

Capture the map view as an image

In certain situations, it may be necessary to save the map as an image - for example, to generate previews that are too expensive to redraw in real time. In this case, the captureImage method can be used. It returns an Image object which can be later exported to different formats.

auto image = mapView->captureAsImage();

if (image.isDefault())
{
GEM_INFO_LOG("Could not capure image");
} else
{
auto pngBuffer = image.exportAs( Size(500, 300), EImageFileFormat::IFF_Png);
}
warning

Capturing the map view as an image may not work correctly when the map rendering is disabled.

tip

To ensure that any ongoing map animations or loading have completed, wait for the callback provided to onViewRendered to be triggered with tivStatus set to EViewDataTransitionStatus::VD_Complete before capturing the image. Make sure to implement a timeout, as the onViewRendered is only triggered when the map is rendering - and will not be called if everything is already loaded.