Adjust the map view
The HERE SDK offers various methods to change the map view. While map styles allow you to alter the appearance of the map, the MapCamera functionality enables you to view the map from different perspectives.
How does it work?
With the HERE SDK, you can set a target location, tilt the camera, zoom in and out, and adjust the bearing angle, among other capabilities.
- Use the
MapCamerareturned bymapView.getCamera()to manipulate the view of the map. - Set a new target location by calling
camera.lookAt(new GeoCoordinates(52.530932, 13.384915)). This instantly switches the map view to the new location. - Get the current center location of the map view by calling
mapView.getCamera().getState().targetCoordinates. - Zoom the map by setting a distance in meters:
mapView.getCamera().lookAt(new GeoCoordinates(52.373556, 13.114358), orientation, new MapMeasure(MapMeasure.Kind.DISTANCE_IN_METERS, distanceInMeters)). Get the current distance from the camera'sStateproperty. TheStateprovides also the current the zoom level. - Set a
GeoOrientationUpdateto specify the tilt angle and bearing angle of the camera. - Set a transform center with
MapCamera.setPrincipalPoint(Point2D)to change the default pivot point that is centered on the map view. - Get the bounds of the currently displayed area by calling
camera.getBoundingBox(). - Set the bounds of an area to display by calling
camera.lookAt(geoBox, new GeoOrientationUpdate(null, null)). Setting null will keep any previous values for bearing and tilt. - Move the map: Run basic animations from A to B with the
MapCameraAnimationFactory. Customize animations by using one of its overloaded methods - for example, useflyTo()for advanced animations.
By default, the camera is located centered above the map. From a bird's eye view looking straight-down, the map is oriented north up. This means that on your device, the top edge is pointing to the north of the map.
Change the camera location
If you want to move the map to a new location with an animation, use the flyTo() method of the MapCameraAnimationFactory. If you want to instantly switch to a new map location, you can do so by setting a new target:
By setting a new camera target, you can change the camera's location and effectively change the location that is shown at the center of the map view. The lookAt() method is available in different overloads. Just a few examples:
// Change only the location.
camera.lookAt(new GeoCoordinates(52.530932, 13.384915));
// Change zoom and location.
double distanceInMeters = 1000 * 2;
MapMeasure mapMeasureZoom = new MapMeasure(MapMeasure.Kind.DISTANCE_IN_METERS, distanceInMeters);
camera.lookAt(new GeoCoordinates(52.530932, 13.384915), mapMeasureZoom);
// Change location area and orientation.
GeoBox geoBox = new GeoBox(new GeoCoordinates(52.373556, 13.114358),
new GeoCoordinates(52.611022, 13.479493));
double bearingInDegress = 0;
double tiltInDegress = 45;
GeoOrientationUpdate orientation =
new GeoOrientationUpdate(bearingInDegress, tiltInDegress);
camera.lookAt(geoBox, orientation);val distanceInMeters = (1000 * 2).toDouble()
val mapMeasureZoom = MapMeasure(MapMeasure.Kind.DISTANCE_IN_METERS, distanceInMeters)
camera.lookAt(GeoCoordinates(52.530932, 13.384915), mapMeasureZoom)
// Change location area and orientation.
val geoBox = GeoBox(
GeoCoordinates(52.373556, 13.114358),
GeoCoordinates(52.611022, 13.479493)
)
val bearingInDegress = 0.0
val tiltInDegress = 45.0
val orientation = GeoOrientationUpdate(bearingInDegress, tiltInDegress)
camera.lookAt(geoBox, orientation)Note that changing the orientation (bearing, tilt) of the camera does not change the location of the map.
NoteThe HERE SDK also supports dedicated zoom levels in the range [0,22] to provide a quick way to achieve the desired level of detail. Call the camera's
zoomTo()method to set the zoom level and access the current zoom level from the camera'sStateproperty. Important: the zoom level is set asDouble, be sure to not mix it with thedistanceInMetersparameter that is also of typeDouble.
By changing the camera, you can only programmatically change the perspective of the map view, but you do not have direct control of the map view itself - like when performing gestures to zoom the map or to rotate or to tilt the map. See the Gestures section for an overview of the available gestures to manipulate the map directly.
NoteA
MapCamerais always in a definedState. For example, theStateis providing the current target location. This target location indicates the current center of the map view - unless the default principal point was changed (see below).
Alternatively, fly to a location with a concave bow animation:
private void flyTo(GeoCoordinates geoCoordinates) {
GeoCoordinatesUpdate geoCoordinatesUpdate = new GeoCoordinatesUpdate(geoCoordinates);
double bowFactor = 1;
MapCameraAnimation animation =
MapCameraAnimationFactory.flyTo(geoCoordinatesUpdate, bowFactor, Duration.ofSeconds(3));
mapCamera.startAnimation(animation);
}private fun flyTo(geoCoordinates: GeoCoordinates) {
val geoCoordinatesUpdate = GeoCoordinatesUpdate(geoCoordinates)
val bowFactor = 1.0
val animation = MapCameraAnimationFactory.flyTo(geoCoordinatesUpdate, bowFactor, Duration.ofSeconds(3))
mapCamera.startAnimation(animation)
}Rotate the camera
With the camera, you cannot rotate the map directly, but change the camera's orientation instead. By changing the bearing parameter of the GeoOrientationUpdate, you will have the same effect as when rotating the map.
The orientation of the map is usually specified by a bearing angle. 'Bearing' is a navigation term, counted in degrees, from the North in a clockwise direction.

Illustration: Bearing direction.
By default, the camera has a bearing value of 0° degrees. By setting a bearing angle of 45°, as visualized in the illustration above, the map appears to the camera's eye as it rotates counter-clockwise and the direction of the bearing becomes the new upward direction on your map, pointing to the top edge of your device. This is similar to holding and rotating a paper map while hiking in a certain direction. Apparently, it is easier to orient yourself if the map's top edge points in the direction in which you want to go. However, this will not always be the true North direction (bearing = 0°).
Note that the bearing axis is always perpendicular to the ground and passes through the camera, regardless of the current camera orientation.
The following code rotates the camera by 90°:
double bearingInDegress = 90;
double tiltInDegress = 0;
GeoOrientationUpdate orientation =
new GeoOrientationUpdate(bearingInDegress, tiltInDegress);
double distanceInMeters = 1000 * 7;
MapMeasure mapMeasureZoom = new MapMeasure(MapMeasure.Kind.DISTANCE_IN_METERS, distanceInMeters);
mapView.getCamera().lookAt(
new GeoCoordinates(52.373556, 13.114358), orientation, mapMeasureZoom);val bearingInDegress = 90.0
val tiltInDegress = 0.0
val orientation = GeoOrientationUpdate(bearingInDegress, tiltInDegress)
val distanceInMeters = (1000 * 7).toDouble()
val mapMeasureZoom = MapMeasure(MapMeasure.Kind.DISTANCE_IN_METERS, distanceInMeters)
mapView.camera.lookAt(GeoCoordinates(52.373556, 13.114358), orientation, mapMeasureZoom)Effectively, for the viewer this lets the map appear rotated by 90° to the left.
Tilt the camera
The camera can also be used to transform the flat 2D map surface to a 3D perspective to see, for example, roads at a greater distance that may appear towards the horizon. By default, the camera is not tilted (tilt = 0°).
In addition to the tilt value of the camera, the camera's bearing angle (see above) can be manipulated. Here we show the effect of changing the tilt value. Look at the illustration below to see the available camera axes.
A tilt value of 0° means that the camera's optical axis is perpendicular to the ground. The tilt angle is always calculated from this perpendicular axis. The tilt angle relates to the optical axis of the camera.
As visualized in the illustration, tilting the camera by 45° will change the bird's eye view of the camera to a 3D perspective. Use the code below to change only the tilt value of the camera:
double bearingInDegress = 0;
double tiltInDegress = 45;
GeoOrientationUpdate orientation = new GeoOrientationUpdate(bearingInDegress, tiltInDegress);
double distanceInMeters = 1000 * 7;
MapMeasure mapMeasureZoom = new MapMeasure(MapMeasure.Kind.DISTANCE_IN_METERS, distanceInMeters);
mapView.getCamera().lookAt(new GeoCoordinates(52.373556, 13.114358), orientation, mapMeasureZoom);val bearingInDegress = 0.0
val tiltInDegress = 45.0
val orientation = GeoOrientationUpdate(bearingInDegress, tiltInDegress)
val distanceInMeters = (1000 * 7).toDouble()
val mapMeasureZoom = MapMeasure(MapMeasure.Kind.DISTANCE_IN_METERS, distanceInMeters)
mapView.camera.lookAt(GeoCoordinates(52.373556, 13.114358), orientation, mapMeasureZoom)As you can see in the illustration below, the tilt angle is calculated from the vertical axis at the target location. The direction pointing straight-down below the observer is called the nadir. Setting a tilt value will effectively move the camera to keep focusing the camera's target.
Note that each tilt value is applied as absolute value and not as delta - this means that subsequent tilt values will be always applied from the camera's default location and not the previous location. Therefore, setting the same tilt value multiple times, will not change the camera's tilt axis. This is common for most camera operations. Values that are out of range will be clamped.

Illustration: Tilt the map.
All axes can be manipulated at the same time.
Note that changing the bearing value will give different results when the camera is tilted - as illustrated below: a tilted camera will lead to a different target location when a bearing value is set, while an untilted camera will keep its target location.

Illustration: The axes of the camera for bearing and tilt.
Change the transform center
By default, the map's pivot point - or principal point - is centered on the map view. It determines the point where the target coordinates are placed within the map view. Setting a new principal point instantly moves the map to render the current target coordinates at the new principal point. It is set in pixels relative to the map view's origin top-left (0, 0).
NoteThe principal point affects all programmatic map transformations (rotate, orbit, tilt and zoom) and the two-finger-pan gesture to tilt the map. Other gestures, like pinch-rotate, are not affected.
Usually, you want to set the principal point only once, for example to lower the transform center a bit during turn-by-turn navigation - so the user can see more of the road ahead. To achieve this, you need to get the pixel dimensions of your map view (based on your layout and the device's screen dimensions) and then lower the height by 3/4, that is multiply mapViewHeightInPixels by 0.75. See the following example:
// Repositions principal point 3/4 lower than default.
double mapViewWidthInPixels = mapView.getWidth();
double mapViewHeightInPixels = mapView.getHeight();
Point2D newTransformCenter = new Point2D(mapViewWidthInPixels / 2, mapViewHeightInPixels * 0.75);
camera.setPrincipalPoint(newTransformCenter);
// Reposition a circle view on screen to indicate the new target.
cameraTargetView.setX((float) newTransformCenter.x - cameraTargetView.getWidth() / 2);
cameraTargetView.setY((float) newTransformCenter.y - cameraTargetView.getHeight() / 2);// Repositions principal point 3/4 lower than default.
val mapViewWidthInPixels = mapView.width.toDouble()
val mapViewHeightInPixels = mapView.height.toDouble()
val newTransformCenter = Point2D(mapViewWidthInPixels / 2, mapViewHeightInPixels * 0.75)
camera.setPrincipalPoint(newTransformCenter)
// Reposition a circle view on screen to indicate the new target.
cameraTargetView.setX(newTransformCenter.x.toFloat() - cameraTargetView.getWidth() / 2)
cameraTargetView.setY(newTransformCenter.y.toFloat() - cameraTargetView.getHeight() / 2)The code snippet above sets a new principal point that will instantly move the current map center down by 3/4 of the visible map area on screen. Once set, all further map manipulations will be pivoted around this new principal point. For example, when you programmatically rotate the map, the map will always rotate around the principal point.
In the example above, we show also how to render a custom cameraTargetView centered on the principal point, the full code for this can be seen in the "Camera" example app.
For the HERE SDK for Android Navigate, note that when using the VisualNavigator, this is different, as the navigator controls the principal point. When you want to use a custom principal point during turn-by-turn navigation, then you have to set this for the CameraBehavior instead of setting this directly on the MapView:
FixedCameraBehavior fixedCameraBehavior = new FixedCameraBehavior();
visualNavigator.setCameraBehavior(fixedCameraBehavior);
// Repositions principal point higher than default during navigation.
Anchor2D newTransformCenter = new Anchor2D(0.5, 0.5);
fixedCameraBehavior.setNormalizedPrincipalPoint(newTransformCenter);val fixedCameraBehavior = FixedCameraBehavior()
visualNavigator.setCameraBehavior(fixedCameraBehavior)
// Repositions principal point higher than default during navigation.
val newTransformCenter = Anchor2D(0.5, 0.5)
fixedCameraBehavior.normalizedPrincipalPoint = newTransformCenterAdd animations
More advanced animation examples can be seen in the [CameraKeyframeTracks](https://github.com/heremaps/here-sdk-examples/tree/master/examples/latest/navigate/android/Java/CameraKeyframeTracks) example app on GitHub.
If you are looking for an example how to zoom to a Route, or a GeoBox, take a look at the routing section. This can be done with or without an animation - including an optional padding.
Customize gestures and camera behavior
By default, the map view supports several gestures that allow users to manipulate the camera by interacting with the map. For example, you can pinch and rotate the map using a two-finger gesture. Each gesture also adjusts the properties of the camera. If you want to customize the default behavior, you can disable any of the supported GestureType actions and define your own camera manipulation.
This can be achieved using customization of gestures, see Add custom zoom behavior.
Try the Camera example app
Most of the code snippets mentioned above are available in our "Camera" example app, provided in both Java and Kotlin. You can find this example app on GitHub.
Updated yesterday