Skip to main content

Adjust the map view

|

The Maps SDK for Android provides multiple ways to modify the map view, center on coordinates or areas, including MapView functionality for exploring different perspectives.

The SDK enables a range of features, including zooming in and out, tilting the camera, centering on specific locations, and more, all through the MapView and MapViewPreferences classes provided by the SDK.

  • Use viewport property to return the current viewport of the map view.
  • Center on specific coordinates with centerOnCoordinates which takes extra parameters for centering preferences such as zoom level, screen position, map angle, animation and more.
  • Center on a specific geographic area represented by a rectangle with coordinates as corners with centerOnArea and centerOnRectArea.
  • Align map according to the north direction by using alignNorthUp.
  • Adjust the current zoom level using setZoomLevel, where lower values result in a more zoomed-out view.
  • Perform a scrolling behavior based on horizontal and vertical scroll offsets with scroll method.
  • MapCamera class provides further functionality such as manipulating orientation, position, and state.

Map viewport

The map viewport refers to the area displayed by the MapView. Getting the current viewport provides a Rect object which consists of x, y (left and top) screen coordinates and width and height.

The top left coordinate of the screen is represented by [0, 0] and bottom right [viewport.width, viewport.height].

// Get MapView from GemSurfaceView
val gemSurfaceView = findViewById<GemSurfaceView>(R.id.gem_surface)
val mapView = gemSurfaceView.mapView

val currentViewport = mapView?.viewport

This viewport can be useful when you need to use methods such as centerOnRectArea.

info

The width and height of the map view is measured in physical pixels. To transform them into logical pixels you may need to consider the device's pixel density.

Map centering

Map centering can be achieved using the centerOnCoordinates, centerOnArea, centerOnRectArea, centerOnRoute, centerOnDistRoute, centerOnRouteInstruction, centerOnRouteTrafficEvent methods.

Map centering on coordinates

In order to center the WGS coordinates on the viewport coordinates you can use the centerOnCoordinates method like so:

// Get MapView from GemSurfaceView
val gemSurfaceView = findViewById<GemSurfaceView>(R.id.gem_surface)
val mapView = gemSurfaceView.mapView

mapView?.centerOnCoordinates(Coordinates(45.0, 25.0))

A linear animation can be incorporated while centering, as demonstrated below:

// Get MapView from GemSurfaceView
val gemSurfaceView = findViewById<GemSurfaceView>(R.id.gem_surface)
val mapView = gemSurfaceView.mapView

mapView?.centerOnCoordinates(
Coordinates(52.14569, 1.0615),
animation = Animation(EAnimation.Linear, 2000)
)
Tip

You can call the skipAnimation() method of MapView to bypass the animation. To check if an animation is in progress the isAnimationInProgress() method can be used. To check if the camera is moving (as a consequence of an animation or not), the isCameraMoving() method can be used.

danger

Do not confuse the zoomLevel with the slippyZoomLevel. The slippyZoomLevel is a value linked with the tile system.

Converting between screen and WGS coordinates

In order to convert a screen position to WGS coordinates, the MapView.transformScreenToWgs() method is used:

// Get MapView from GemSurfaceView
val gemSurfaceView = findViewById<GemSurfaceView>(R.id.gem_surface)
val mapView = gemSurfaceView.mapView

val coordsToCenter = mapView?.transformScreenToWgs(Xy(pos.x, pos.y))

coordsToCenter?.let {
mapView?.centerOnCoordinates(it, zoomLevel = 70)
}
info

If the applied style includes elevation and terrain data is loaded, the transformScreenToWgs method returns Coordinates objects that include altitude.

To convert WGS coordinates to screen coordinates, the MapView.transformWgsToScreen() method is used:

// Get MapView from GemSurfaceView
val gemSurfaceView = findViewById<GemSurfaceView>(R.id.gem_surface)
val mapView = gemSurfaceView.mapView

val wgsCoordinates = Coordinates(8.0, 25.0)

val screenPosition = mapView?.transformWgsToScreen(wgsCoordinates)
Tip

In order to convert a screen rectangle to a list of WGS geographic areas, use MapView.transformScreenToWgsListArea method.

This centers the view precisely on the specified coordinates, positioning them at the cursor position (which by default is in the center of the screen).

Map centering on coordinates at given screen position

To center on a different area of the viewport (not the cursor position), provide an xy parameter, represented as an Xy. Note that x coordinate should be in [0, viewport.width] and y coordinate between [0, viewport.height].

danger

The xy parameter is defined in physical pixels.

The following example demonstrates how to center the map at one-third of its height:

// Get MapView from GemSurfaceView
val gemSurfaceView = findViewById<GemSurfaceView>(R.id.gem_surface)
val mapView = gemSurfaceView.mapView

val physicalHeightPixels = mapView?.viewport?.height ?: 0
val physicalWidthPixels = mapView?.viewport?.width ?: 0

mapView?.centerOnCoordinates(
Coordinates(52.48209, -2.48888),
zoomLevel = 40,
xy = Xy(physicalWidthPixels / 2, physicalHeightPixels / 3)
)
Centered at one-third of map height
Tip

More parameters such as animation, mapAngle, viewAngle and zoomLevel can be passed to the method in order to achieve a higher level of control.

Map centering on area

Centering can be done on a specific RectangleGeographicArea which consists of top left and bottom right coordinates.

// Get MapView from GemSurfaceView
val gemSurfaceView = findViewById<GemSurfaceView>(R.id.gem_surface)
val mapView = gemSurfaceView.mapView

val topLeftCoords = Coordinates(44.93343, 25.09946)
val bottomRightCoords = Coordinates(44.93324, 25.09987)
val area = RectangleGeographicArea(topLeftCoords, bottomRightCoords)

mapView?.centerOnArea(area)

This will center the view on the geographic area ensuring the RectangleGeographicArea covers most of the viewport. For centering the geographic area on a particular coordinate of the viewport, the xy parameter, represented as an Xy should be provided.

Alternatively, to center the RectangleGeographicArea on a specific region of the viewport, you can use the centerOnRectArea method. This requires passing the viewRc parameter, represented as a Rect, which defines the targeted region of the screen. The Rect passed to the viewRc parameter determines the positioning of the centered area relative to the top-left coordinates. Consequently, the bottom-right corner will be at left + Rect's width and top + Rect's height.

info

As the width and height of Rect decrease, the centering will result in a more zoomed-out view. For a more zoomed-in perspective, use larger values within the range [1, viewport.width - x] and [1, viewport.height - y].

Tip

Use the getOptimalRoutesCenterViewport and getOptimalHighlightCenterViewport methods to compute the viewport region that best fits given routes and highlights.

Map centering on area with padding

Centering on an area using padding can be done by altering the screen coordinates (in physical pixels) by adding/subtracting the padding value. Then a new RectangleGeographicArea object needs to be instantiated with the padded screen coordinates transformed into WGS coordinates using MapView.transformScreenToWgs(xy).

The following code exemplifies the process:

// Get MapView from GemSurfaceView
val gemSurfaceView = findViewById<GemSurfaceView>(R.id.gem_surface)
val mapView = gemSurfaceView.mapView

// Getting the RectangleGeographicArea in which the route belongs
val routeArea = route.geographicArea
val paddingPixels = 200

// Getting the top left point screen coordinates in physical pixels
val routeAreaTopLeftPoint = mapView?.transformWgsToScreen(routeArea.topLeft)

// Adding padding by shifting point in the top left
val topLeftPadded = routeAreaTopLeftPoint?.let { point ->
Xy(
point.x - paddingPixels,
point.y - paddingPixels
)
}

val routeAreaBottomRightPoint = mapView?.transformWgsToScreen(routeArea.bottomRight)

// Adding padding by shifting point downwards three times the padding
val bottomRightPadded = routeAreaBottomRightPoint?.let { point ->
Xy(
point.x + paddingPixels,
point.y + 3 * paddingPixels
)
}

// Converting points with padding to WGS coordinates
val paddedTopLeftCoordinate = topLeftPadded?.let { mapView?.transformScreenToWgs(it) }
val paddedBottomRightCoordinate = bottomRightPadded?.let { mapView?.transformScreenToWgs(it) }

if (paddedTopLeftCoordinate != null && paddedBottomRightCoordinate != null) {
mapView?.centerOnArea(
RectangleGeographicArea(
paddedTopLeftCoordinate,
paddedBottomRightCoordinate
)
)
}
Route without padding
Route with center padding

danger

When applying padding, note that the height is measured in physical pixels. A conversion may be required depending on your use case.

Map zoom

To get the current zoom level use the zoomLevel property. A bigger value means the camera is closer to the terrain. Changing the zoom level is done through the setZoomLevel method of the MapView class in the following way:

// Get MapView from GemSurfaceView
val gemSurfaceView = findViewById<GemSurfaceView>(R.id.gem_surface)
val mapView = gemSurfaceView.mapView

val zoomLevel = mapView?.zoomLevel
mapView?.setZoomLevel(50)

The maximum allowed zoom level can be accessed via the maxZoomLevel property from the MapView class. In order to check if a particular zoom level can be applied, check if it's within the valid range.

Map rotation angle

To get the current rotation angle of the map, use the rotationAngle property from the MapViewPreferences class. Changing the rotation angle is done through the rotationAngle setter of MapViewPreferences like so:

// Get MapView from GemSurfaceView
val gemSurfaceView = findViewById<GemSurfaceView>(R.id.gem_surface)
val mapView = gemSurfaceView.mapView

val rotationAngle = mapView?.preferences?.rotationAngle ?: 0.0
mapView?.preferences?.rotationAngle = 45.0

The provided value needs to be between 0 and 360. By default, the camera has a rotation angle value of 0 degrees corresponding to the north-up alignment. Note that the rotation axis is always perpendicular to the ground and passes through the camera, regardless of the current camera orientation.

Map view angle

The camera can transform the flat 2D map into a 3D perspective, allowing you to view features like distant roads appearing on the horizon. By default, the camera has a top-down perspective (viewAngle = 90°).

In addition to adjusting the camera's view angle, you can modify its tilt angle. The tiltAngle is defined as the complement of the viewAngle, calculated as tiltAngle = 90-viewAngle

In order to change the view angle of camera you need to access the preferences field of MapView like so:

// Get MapView from GemSurfaceView
val gemSurfaceView = findViewById<GemSurfaceView>(R.id.gem_surface)
val mapView = gemSurfaceView.mapView

val viewAngle = mapView?.preferences?.viewAngle ?: 30
mapView?.preferences?.setViewAngle(45)
Map with a view angle of 60 degrees
Map with a view angle of 0 degrees

To adjust the camera's perspective dynamically, you can utilize both the tiltAngle and viewAngle properties.

The difference between the different types of angles is shown below:

Tilt angle & view angle
Rotation angle

info

Keep in mind that adjusting the rotation value produces different outcomes depending on the camera's tilt. When the camera is tilted, changing the rotation will shift the target location, whereas with no tilt, the target location remains fixed.

Map perspective

Map perspective can be either two dimensional or three dimensional and can also be set by using MapViewPreferences method setMapViewPerspective:

// Get MapView from GemSurfaceView
val gemSurfaceView = findViewById<GemSurfaceView>(R.id.gem_surface)
val mapView = gemSurfaceView.mapView

val perspective = mapView?.preferences?.mapViewPerspective ?: EMapViewPerspective.ThreeDimensional
mapView?.preferences?.setMapViewPerspective(EMapViewPerspective.ThreeDimensional)

By default, the map perspective is three-dimensional.

Map with a two-dimensional perspective
Map with a three-dimensional perspective

A three-dimensional perspective gives buildings a realistic, 3D appearance, while a two-dimensional perspective makes them appear as flat shapes.

info

To ensure three-dimensional buildings are visible, the camera angle should not be perpendicular to the map. Instead, the view angle must be less than 90 degrees.

The same effect can be implemented more precisely using the tiltAngle/viewAngle fields.

Building visibility

Building visibility can be controlled using the buildingsVisibility property from the MapViewPreferences class:

  • EBuildingsVisibility.Default: Uses the default visibility defined in the map style.
  • EBuildingsVisibility.Hide: Hides all buildings.
  • EBuildingsVisibility.TwoDimensional: Displays buildings as flat 2D polygons without height.
  • EBuildingsVisibility.ThreeDimensional: Displays buildings as 3D polygons with height.
// Get MapView from GemSurfaceView
val gemSurfaceView = findViewById<GemSurfaceView>(R.id.gem_surface)
val mapView = gemSurfaceView.mapView

val visibility = mapView?.preferences?.buildingsVisibility ?: EBuildingsVisibility.Default
mapView?.preferences?.buildingsVisibility = EBuildingsVisibility.TwoDimensional

Buildings become visible when the camera is zoomed in close to the ground. The 3D effect is most noticeable when viewed from a tilted angle. Note that the 3D buildings do not reflect realistic or accurate heights.

Store and restore a view

The map camera object has properties and methods for position and orientation ensuring a high level of control over the map view.

For storing a particular view the saveCameraState method can be used. This method returns a DataBuffer object and depending on the use case this can be stored inside a variable or serialized to a file.

val state = mapView.camera?.saveCameraState()

Restoring a saved view can be done easily using the restoreCameraState method:

state?.let {
mapView.camera?.restoreCameraState(it)
}

Alternatively the position and orientation can be stored and restored separately using the provided properties.

info

Please note that saveCameraState does not contain information about the current style.

Download individual map tiles

A map tile is a small, rectangular image or data chunk that represents a specific geographic area at a particular zoom level on a MapView. Tiles are usually downloaded when panning or zooming in on a map, and they are used to render the map's visual content. However, you can also download tiles that are not currently visible on the screen, using the MapDownloaderService class.

Configuring the MapDownloaderService

The service can be configured by setting specific maximum area size in square kilometers to download by using the maxSquareKm property:

val service = MapDownloaderService()

// Set a new value
service.maxSquareKm = 100

// Verify the new value
val updatedMaxSquareKm = service.maxSquareKm

The larger the area, the more tiles can be downloaded, which can lead to increased memory usage. The default value is 1000 square kilometers.

danger

If the RectangleGeographicArea surface exceeds the maxSquareKm, the MapDownloaderService will return GemError.OutOfRange.

Downloading tiles is done by calling the startDownload method of MapDownloaderService like so:

val service = MapDownloaderService()

service.maxSquareKm = 300

val areas = arrayListOf(
// Area in which the tiles will be downloaded that is under 300 square kilometers
RectangleGeographicArea(
Coordinates(67.69866, 24.81115),
Coordinates(67.58326, 25.36093)
)
)

service.startDownload(areas, object : ProgressListener() {
override fun notifyComplete(errorCode: ErrorCode, hint: String) {
// Handle completion
}
})

When tiles are downloaded, the notifyComplete callback is invoked with an ErrorCode parameter indicating the success or failure of the operation. If the download is successful, the error will be ErrorCode.Success. Downloaded tiles are stored in the cache and can be used later for features such as viewing map content without requiring an internet connection.

Downloaded tiles centered in the middle, top and bottom tiles are not available
info

SearchService.search method will return an error when trying to search in a downloaded tiles area as it requires indexing, which is not available for downloaded tiles.

Download can be canceled by calling the cancelDownload method of MapDownloaderService and the notifyComplete callback will be invoked with ErrorCode.Cancelled.

Tip

Trying to download previously downloaded tiles will not result in an error, as downloaded tiles are present inside the application's cache folder as data files.

You can access detailed download statistics for map tiles using the transferStatistics property.

danger

Downloaded map tiles via MapDownloaderService do not support operations such as free-text search, routing, or turn-by-turn navigation while offline. They are primarily intended for caching map data for visual display purposes only.

For full offline functionality, including search and navigation, refer to the Manage Offline Content Guide to learn how to download roadmap data designed for full offline use.

Change map settings while following the current position

The FollowPositionPreferences class provides more customization while the camera is in the follow position mode. To retrieve an instance, use the snippet below:

val preferences = mapView.preferences?.followPositionPreferences

See the customize follow position settings guide for more details.