Skip to content

Map

The core feature of the Sygic Maps SDK is Maps. The key concepts covered in this section include adding a map to an Android application, changing the location displayed by the map and its various properties. The classes covered include MapFragment and MapView. The MapFragment is a standard Android Fragment derived component. MapView is a class for controlling the displayed map. To obtain an instance of MapView call the asynchronous MapFragment.getMapAsync():

mapFragment.getMapAsync(new OnMapInitListener() {
    @Override
    public void onMapInitializationInterrupted() {}

    @Override
    public void onMapReady(@NonNull final MapView mapView) {
        // now you can use the returned MapView
    }
});

Once the map is ready, you can get the MapView synchronously, using the MapFragment.getMapView(). For example, the following code snippet illustrates how to render the Map at London, UK:

// get MapView
MapView map = mapFragment.getMapView();

// Set the map center to London, UK.
map.getCameraModel().setPosition(new GeoCoordinates(51.509865, -0.118092));

To enable online maps, you need to get the OnlineManager using the OnlineManagerProvider.getInstance() and then call enableOnlineMapStreaming on the onlineManager instance. To display offline maps, see Offline Maps

In the preceding code the GeoCoordinates for the map center is created by a call to the new GeoCoordinates(double, double) constructor.

Map Handling

Once the MapView is initialized, it can be manipulated and interacted in a variety of ways. Some key attributes of the MapView are its orientation, tilt, geographical center (geoCenter), and zoom level (zoom). You can use these to customize the displayed map via the Camera class.

Zoom Level

The size of the geographical area displayed by Map can be controlled by changing the zoom level. The values can be in the interval between 0 and 20.

// Set the zoom to for example 18.5.
map.getCameraModel().setZoomLevel(18.5f);

// Get the zoom level, should be 18.5.
float zoom = map.getCameraModel().getZoomLevel();

Rotation

The map can be orientated in any direction. By default, the rotation is in a true North position. The following code changes the orientation to South-up.

// Rotate by 180 degrees.
map.getCameraModel().setRotation(180);

// Get the rotation that you have set above - the returned value should be 180.
float rotation = map.getCameraModel().getRotation();

Tilt

The map can be tilted and rendered in a three-dimensional perspective. By default, the tilt is completely flat.

// Set the tilt to 45 degrees
map.getCameraModel().setTilt(45);

// Get the tilt
float tilt = map.getCameraModel().getTilt();

Camera modes

You can set Camera to change position or rotation automatically by setting an appropriate mode. Using the Camera.MovementMode.FollowGpsPositionWithAutozoom, the camera follows the vehicle automatically. If you use this option along with the vehicle rotation set to Vehicle, the camera will rotate according to the vehicle's heading and it will also zoom in when approaching a junction and then zoom out. Below is an example of how to set this.

map.getCameraModel().setMovementMode(Camera.MovementMode.FollowGpsPositionWithAutozoom);
map.getCameraModel().setRotationMode(Camera.RotationMode.Vehicle);

Tilt used to display 3D or 2D mode

Camera listeners

If you want to be notified about certain events, you can simply add camera listeners this way:

map.getCameraModel().addModeChangedListener(new Camera.ModeChangedListener() {
    @Override
    public void onMovementModeChanged(@Camera.MovementMode int mode) {
        switch (mode) {
            case Camera.MovementMode.Free:
                //your code
            case Camera.MovementMode.FollowGpsPosition:
                //your code
            case Camera.MovementMode.FollowGpsPositionWithAutozoom:
                //your code
        }
    }

    @Override
    public void onRotationModeChanged(@Camera.RotationMode int mode) {
        switch (mode) {
            case Camera.RotationMode.Free:
            case Camera.RotationMode.NorthUp:
            case Camera.RotationMode.Attitude:
            case Camera.RotationMode.Vehicle:
                //your code
        }
    }
});

or

map.getCameraModel().addPositionChangedListener(new Camera.PositionChangedListener() {
    @Override
    public void onPositionChanged(final GeoCoordinates geoCenter, final float zoom, final float rotation, final float tilt) {
        //your code here
    }

    @Override
    public void onPositionChangeCompleted() {
        //your code here
    }
});

If you no longer need listeners, for instance OnDestroy, don't forget to unregister the listeners as well:

map.getCameraModel().removeModeChangedListener(this);
map.getCameraModel().removePositionChangedListener(this);

Default map click handling

Touches on map are handled internally by the MapFragment. If you want to perform an action on click (like displaying a context menu, a bubble on the map, etc.), you have to register a MapGestureListener. We also provide the MapGestureAdapter class that provides default implementations so you can override only the methods that you need.

MapView map = mapFragment.getMapView();
map.addMapGestureListener(new MapGestureAdapter() {

    @Override
    public boolean onMapClicked(final MotionEvent e, final boolean isTwoFingers) {
        // do something...
        return true;
    }
});

This will override only the onMapClicked() method. Calling true as return value will prevent delegating onMapClick to SDK. Then you can get the GeoCoordinates from the place where you tapped on the screen,

final MapView map = mapFragment.getMapView();
GeoCoordinates get = map.geoCoordinatesFromPoint(x, y);

where {x, y} are screen coordinates of point inside of the MapFragment (obtained for example from MotionEvent.getX() and getY()).

Initial map state

By default, the map will show a whole globe after initialization. If you are adding the fragment dynamically in code, you can use factory method MapFragment.newInstance() and pass it your wanted initial CameraState.

final CameraState.Builder cameraState = new CameraState.Builder();
cameraState.setPosition(new GeoCoordinates(40.730655, -73.997437));
cameraState.setZoomLevel(18.5f);
MapFragment.newInstance(cameraState.build());

FPS Configuration

You can set a custom FPS (frames per second) configuration. You can choose between two modes - Balanced and Performance. These two modes are affected by the targetFps value. If you choose the Performance mode, the engine always tries to achieve the targetFps value. If you choose the Balanced mode, the targetFps value is the lowest the engine should go in order to preserve battery life. The default is Balanced at 15FPS.

Let's see how to set the FpsConfig for the map to always try to run at 60fps:

mMapView.fpsLimit = FpsConfig(FpsConfig.FpsMode.PERFORMANCE, 60f)

Map Schemes

There are some map schemes available so you can offer a different kind of map appearance to your users. The list of available schemes can be obtained by:

final List<String> availableSkins = map.getAvailableSkins();

Some of the options are "default", "day", "night", "car", "pedestrian". The schemes can be combined as they are only incremental. More info on scheme configuration and possibility to create own schemes is coming soon.

map.getMapDataModel().setSkin(Arrays.asList("day", "pedestrian", "default"));

Day Skin / Night Skin

Sygic Maps SDK does not automatically switch map schemes during navigation mode. Before starting car or pedestrian navigation, be sure to save the current map scheme and switch to the appropriate navigation map scheme.

Gestures

The MapView class responds to a number of predefined touch gestures. The default behavior of the map for each gesture type may be used as-is, supplemented, or replaced entirely. The following table is a summary of the available gestures and their default behavior.

Gesture Description Following gestures
Rotate Rotate: Two-finger press, simultaneously orbit both fingers around the center point, lift Pinch, Spread, Move
Zoom out Pinch: Two-finger press, move inwards, lift Spread, Rotate, Move
Zoom in Spread: Two-finger press, move outwards, lift
Move Swipe: One-finger press, move, lift/don't lift
Tilt Tilt: Two fingers press, move up (increase the tilt angle) or move down (decrease the tilt angle)
Short touch Short touch: One-finger press, lift

Map input like map dragging, map rotation, map tilt, map zoom is handled internally by MapFragment. However you can override default behavior by setting your own listener:

MapView map = mapFragment.getMapView();
map.addMapGestureListener(new MapGestureAdapter() {
    @Override
    public boolean onMapMove(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
        // do something...
        return true;
    }
});

Set the return value to true if the listener has consumed the event, false otherwise. If false is returned, the default gesture action will be executed.

GeoBoundingBox

Defines a rectangular area in a geographic coordinate system. It is defined by the GeoCoordinates of its left top corner and of its right bottom corner. For example a bounding box of London would be defined like this:

val topLeft = GeoCoordinates(51.692701, -0.561623)
val bottomRight = GeoCoordinates(51.303139, 0.380848)
val boundingBox = GeoBoundingBox(topLeft, bottomRight)

Objects and Interaction

The Sygic Maps SDK allows the addition of a variety of objects, each with a specific purpose, to a map view. The types of available objects include map markers, routes, polylines, circles, polygons. To see all the objects check the MapObject.MapObjectType. Some objects are described in more detail below.

In order to display the map object on the map, the object needs to be added to a MapView's data model by calling addMapObject(). The objects are initialized using a builder.

MapCircle

Enables you to draw a circle on the map at a fixed geographical location. You can customize you circle's color, radius, lineColor - see the MapCircle API reference for more information.

MapCircle circle = MapCircle.at(new GeoCoordinates(51.509865, -0.118092))
                            .setRadius(200)
                            .build();
map.getMapDataModel().addMapObject(circle);

// you can remove the circle like this
map.getMapDataModel().removeMapObject(circle);

Circle

MapPolyline

Enables you to draw one or more connected line segments on the map. The segment vertices are specified by a series of GeoCoordinates. The visual appearance of the polyline can also be customized. See the MapPolyline API reference for more information.

MapPolyline polyline = MapPolyline.of(Arrays.asList(
                                      new GeoCoordinates(51.509, -0.118),
                                      new GeoCoordinates(51.524, -0.137),
                                      new GeoCoordinates(51.572, -0.092)))
                                  .build();
map.GetMapDataModel().addMapObject(polyline);

// remove the polyline
map.GetMapDataModel().removeMapObject(polyline);

Polyline

MapMarker

With Sygic Maps SDK, you can display an icon at a fixed geographical position on the map.

MapMarker marker = MapMarker.at(new GeoCoordinates(51.509865, -0.118092)
                            .build();
map.GetMapDataModel().addMapObject(marker);

// remove the marker
map.GetMapDataModel().removeMapObject(marker);

Marker

You can also provide your own image by using the BitmapFactory class. SDK provides two factories for creating markers from Bitmap or Drawable.

MapMarker marker1 = MapMarker.at(new GeoCoordinates(51.509865, -0.118092)
                                 .withIcon(new DrawableFactory(R.drawable.ic_marker))
                                 .build();

Bitmap bitmap = getBitmap();
MapMarker marker2 = MapMarker.at(new GeoCoordinates(51.515436, -0.122045)
                                 .withIcon(new BitmapFactory(bitmap))
                                 .build();

MapPolygon

A MapPolygon can be displayed on the map since the version 17. You can customize the border/center colors, their radiuses or its center.

ArrayList<GeoCoordinates> geolist = new ArrayList<>();
geolist.add(new GeoCoordinates(48.164498, 17.160628));
geolist.add(new GeoCoordinates(48.141367, 17.099931));
geolist.add(new GeoCoordinates(48.113529, 17.124068));
geolist.add(new GeoCoordinates(48.126849, 17.199407));
geolist.add(new GeoCoordinates(48.145362, 17.164499));


MapPolygon mapPolygon = MapPolygon.of(new GeoCoordinates(48.147267, 17.150949), geolist)
  .setCenterColor(Color.TRANSPARENT)
  .setBorderRadius(0.999999f)
  .setCenterRadius(0.95f)
  .setBorderColor(Color.BLUE)
  .build();
mapDataModel.addMapObject(mapPolygon);

MapSmartLabel

A MapSmartLabel is a map object using which you can show text in a label that' i pinned to the route. It is mostly used when displaying the route's duration while choosing between different routes. A MapSmartLabel is created in the following example with the help of an already-computed route. You can read how to compute a route in the Routing section.

mMapView.mapDataModel.addMapObject(
    MapSmartLabel.with(mRoute)
        .setMaxImageSize(900, 700)
        .setMaxZoomLevel(17f)
        .setText(
            (StyledText(
                formatDate(
                    mRoute.routeInfo.durationWithSpeedProfileAndTraffic
                )
            ))
        )
        .build()
)

Setting a camera map rectangle

It is possible to set a map center using a MapRectangle or using a GeoBoundingBox. For example, this is how you zoom onto a route with 15% margins from each side of the display. The first example is using a MapRectangle, which uses a previously computed route's bounding box and has its own margin definitions. The second one uses just the GeoBoundingBox and the margins are defined after that.

// first example
mMapView.cameraModel.setMapRectangle (
    MapRectangle (
        mRoute.boundingBox,
        0.15f,
        0.15f,
        0.15f,
        0.15f
    ),
    MapAnimation (
        500,
        MapAnimation.InterpolationCurve.AccelerateDecelerate
    )
)

// second example
mMapView.cameraModel.setMapRectangle (
    mRoute.boundingBox,
    0.15f,
    0.15f,
    0.15f,
    0.15f,
    MapAnimation (
        500,
        MapAnimation.InterpolationCurve.AccelerateDecelerate
    )
)

Disabling visibility of objects

It is possible that you would not want to see some of the objects that are shown directly in the map by default, such as 3D buildings, POIs or even roads. You can simply disable them like this:

mMapView.mapDataModel.setMapLayerCategoryVisibility(MapView.MapLayerCategory.Roads, false) // disables visibility of roads
mMapView.mapDataModel.setMapLayerCategoryVisibility(MapView.MapLayerCategory.Landmarks, false) // disables visibility of 3D buildings (landmarks)

To enable them back again, simply call the same code passing a "true" value.

Requesting objects from map

To query what objects are displayed on map, you can call method MapView.requestObjectsAtPoint(). You can for example use a point returned from onMapClicked().

mapView.addMapGestureListener(new MapGestureAdapter() {
    @Override
    public boolean onMapClicked(final MotionEvent e, final boolean isTwoFingers) {
        mapView.requestObjectsAtPoint(e.getX(), e.getY(), new RequestObjectCallback() {
            @Override
            public void onRequestResult(@NonNull final List<ViewObject> objects, final float x, final float y) {

            }
        });

        return true;
    }
});

In the objects parameter there will be a list of objects, as multiple objects can be displayed in the same area. They can have following types:

ScreenObject

This is the basic object that will be returned from every call to requestObjectsAtPoint(). It has only GeoCoordinates that can be retrieved using a getPosition() call.

MapObjects

This can be any object mentioned previously in Objects and Interaction that was added to map.

ProxyObjects

These are objects rendered by map, such as Places (previously Points of Interest) (ProxyPlace) or cities (ProxyCity). Additional information about Places can be loaded via ProxyObjectManager.PlaceLinkListener():

placeLinkListener = new ProxyObjectManager.PlaceLinkListener() {
    @Override
    public void onPlaceLinkLoaded(@NotNull PlaceLink placeLink) {
        String category = placeLink.getCategory();
        String name = placeLink.getName();
        PlacesManagerProvider.getInstance(new CoreInitCallback<PlacesManager>() {
        @Override
        public void onInstance(@NonNull PlacesManager placesManager) {
            placesManager.loadPlace(placeLink, new PlacesManager.PlaceListener() {
            @Override
            public void onPlaceLoaded(@NotNull Place place) {
                List<PlaceDetail> placeDetails = place.getDetails();
            }
            @Override
            public void onPlaceError(@NotNull PlacesManager.ErrorCode errorCode) {
            }
        });
        }
        @Override
        public void onError(@NotNull CoreInitException e) {
        }
        });
    }
    @Override
    public void onPlaceLinkError(@NotNull PlacesManager.ErrorCode errorCode) {
    }
};

In release 17.1.0 a new functionality has been added - BreadCrumbs. When you move, it shows a "trail" behind your vehicle. Please note that you need to turn this function on in the JSON configuration for it to be active. You can also set it in the builder: SygicEngine.JsonConfigBuilder().mapSettings().breadcrumbsEnabled(true). Let's see how to use BreadCrumbs - at first you need to have a mapView. After that, just call the MapView's getBreadCrumbs() and also make sure that it's not null:

mMapView.breadCrumbs?.start() // to start showing the bread crumbs on map
mMapView.breadCrumbs?.setVisibility(BreadCrumbs.Visibility.Hidden) // to hide the visibility
mMapView.breadCrumbs?.clear() // to delete the visible bread crumbs path - this does not stop it!
mMapView.breadCrumbs?.stop() // this stops the logging

Logistic Information

If the maps that you are using contain logistic information, you can show the info in the map. For example, if there's an exception for trucks that contain hazardous materials, the whole route will be greyed-out with an icon over it. If you choose "Truck" as the vehicle for which the logisticInfo should be applied, the roads which are not accessible for truck will be grey, too.

All you need to do is to create a LogisticInfoSettings object and set it to the mapView. Let's see how to do it and more:

val logisticInfoSettings = LogisticInfoSettings()
logisticInfoSettings.vehicleType = LogisticInfoSettings.VehicleType.Truck
logisticInfoSettings.hazmatTypes = RoutingOptions.HazardousMaterialsClass.GoodsHarmfulToWater
logisticInfoSettings.maximumHeight = 3500 // in centimeters
logisticInfoSettings.vehicleWeight = 40000 // in kilograms
mMapView.setLogisticInfoSettings(logisticInfoSettings)

On top of that, you can change the appearance of several images, like this:

val image = RestrictionImage.Builder(R.drawable.xxxxxx).build()
logisticInfoSettings.setLogisticRestrictionImage(RestrictionImage.Config.create(MapView.CountrySignage.World, LogisticInfoSettings.IconType.VehicleWidth), image)

Incident Warning settings

It's possible that you would want to override the images of the incidents that are shown in the map. These are the icons of speed cameras, school zones etc., that keep popping up and disappear after several hours. At first, you will need to create a class that inherits from a BitmapFactory or Drawable factory and override the methods where the bitmap is created and use your own. In this example we won't create one but we will directly call it IncidentBitmapFactory. Consider this code:

fragment.getMapAsync(object : OnMapInitListener {
    override fun onMapInitializationInterrupted() {
    }

    override fun onMapReady(mapView: MapView) {
        // the best way is to extract this into a method and use it in the onMapReady() callback
        val incidentWarningSettings = IncidentWarningSettings()
        incidentWarningSettings.setImageOffset(0.5F, 1f)
        // you can choose if you want to see different incident images while browsing the map or only while navigating
        // we choose "Both" in this example
        incidentWarningSettings.usage = IncidentWarningSettings.Usage.Both
        // now we can set the images for different types of incidents
        // all incident types can be found in the IncidentType class
        incidentWarningSettings.setIncidentImage(IncidentType.Crash, IncidentBitmapFactory(R.drawable.crashImage))
        incidentWarningSettings.setIncidentImage(IncidentType.Police, IncidentBitmapFactory(R.drawable.policeImage))
        // and now just set it to the MapView that you got in the onMapReady() callback
        mapView.setIncidentWarningSettings(incidentWarningSettings)
    }
})