Custom Map Styles

The HERE SDK for Android provides a flexible solution to customize the map by loading custom map schemes.

If you are looking for predefined map styles, see the Quick Start guide for an introduction. The HERE SDK already includes a set of pre-configured map styles such as MapStyle.NORMAL_DAY or MapStyle.SATELLITE.

Create and Load Custom Map Styles

The most flexible solution to customize the map is to create your own map styles using a configuration file generated with the WYSIWYG HERE Style Editor.

Note

A new version of the HERE Style editor will be made available in June. Please wait until then. Note that the resulting map styles are not compatible with the existing web editor, so only the new HERE Style Editor can be used with the HERE SDK.

This HERE SDK release is compatible with the HERE Style Editor 0.64. It is recommended to use the latest style editor and to update existing styles in case of unexpected behavior or errors.

Usually, the HERE Style Editor is updated for each new release. In practice, consider to re-export existing custom map styles with the matching version of the HERE Style Editor. This should be checked whenever you integrate a newer HERE SDK version. Note that some map features like 3D landmarks are only available for specific versions. As a rule of thumb, we recommend to get in touch with your HERE representative to discuss potential style updates for each new release.

Screenshot: The HERE Style Editor showing a custom map configuration.

As soon as you are satisfied with your custom map style, export it via File -> Export -> Here Rendering Engine Configuration. Please unzip the resulting file. You will find a few JSON files.

Copy all JSON files into the "assets" directory of your project. If not already added, you can add that folder via Android Studio (Right-click on the project: New -> Folder -> Assets folder). You can also manually generate the folder.

The main style file always ends with *.scene.json.

Load the style into a map scene as follows:

private void loadMapStyle() {
    // Place the style into the "assets" directory.
    // Full path example: app/src/main/assets/mymapstyle.scene.json
    // Adjust file name and path as appropriate for your project.
    String fileName = "omv/omv-traffic-traffic-normal-night.scene.json";
    AssetManager assetManager = context.getAssets();
    try {
        assetManager.open(fileName);
    } catch (IOException e) {
        Log.e("CustomMapStylesExample", "Error: Map style not found!");
        return;
    }

    mapView.getMapScene().loadScene("" + fileName, new MapScene.LoadSceneCallback() {
        @Override
        public void onLoadScene(@Nullable MapError mapError) {
            if (mapError == null) {
                // Scene loaded.
            } else {
                Log.d("CustomMapStylesExample", "onLoadScene failed: " + mapError.toString());
            }
        }
    });
}

In the above snippet, we use Android's AssetManager to verify that the *.scene.json file exists at the expected location. You only have to load this file. From there, the HERE SDK will find the other files - as exported from the editor. Make sure that all style files are kept together at the same folder level. *.scene.json is the main file that includes references to the other files.

Screenshot: Another example for a custom map style configuration.

Using custom map styles can be very effective to differentiate your app from other map applications. In addition, it is possible to change map styles on-the-fly, for example, to shift the user's attention to certain map elements based on the current state of your app.

Note

You can find a CustomMapStyles example app on GitHub.

Load Custom Raster Layers

Another alternative to customize the map's look is to add your own raster tile service on top of the HERE map styles. This can be your own server where you host tiles that you want to show as an overlay on top of selected areas of the world - or a public tile server such as OpenStreetMap. Fully opaque and transparent map tile overlays are supported. It is also possible to add more than one raster layer to the map at the same time.

Note

Note that this is a beta release of this feature, so there could be a few bugs and unexpected behaviors. Related APIs may change for new releases without a deprecation process.

To add custom raster layers, you need to create a RasterDataSource. A RasterDataSource represents the source of raster tile data to display. It also allows changing its configuration. With a RasterDataSourceConfiguration you can specify a configuration for the data source, including URL, tiling scheme, storage levels and caching parameters.

Finally, with the MapLayerBuilder you can create a MapLayer to add a renderable map overlay to the map.

  • Use MapLayerVisibilityRange to specify at which zoom levels the map layer should become visible.
  • Use the MapLayerPriority to specify the draw order of the MapLayer.
  • Use the MapContentType to specify the type of data to be shown by the MapLayer.

In case of raster tile images, use MapContentType.RASTER_IMAGE.

Default map gesture actions such as pinch, rotate and zoom behave in the same way for raster tiles as for HERE vector maps - except for a few differences: For example, raster tiles are loaded as bitmaps and therefore a rotated raster map tile rotates all labels and street names contained together with the tile.

Note

When loading a map scene with a custom map style or the default map style, the map will be rendered using vector tiles where the map information is represented as vector data consisting of vertices and paths for better scalability and performance. By contrast, raster tiles are regularly-spaced and square, and consist of bitmap images that represent only pixel information. Note that the satellite map style is also raster based.

Create a RasterDataSource as follows:

private RasterDataSource createRasterDataSource(String dataSourceName) {
    // The URL template that is used to download tiles from the device or a backend data source.
    String templateUrl = "https://stamen-tiles.a.ssl.fastly.net/toner/{z}/{x}/{y}.png";
    // The storage levels available for this data source. Supported range [0, 31].
    List<Integer> storageLevels = Arrays.asList(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16);
    RasterDataSourceConfiguration.Provider rasterProviderConfig = new RasterDataSourceConfiguration.Provider(
            templateUrl,
            TilingScheme.QUAD_TREE_MERCATOR,
            storageLevels);

    // Raster tiles are stored in a separate cache on the device.
    String path = "cache/raster/toner";
    long maxDiskSizeInBytes = 1024 * 1024 * 32;
    RasterDataSourceConfiguration.Cache cacheConfig = new RasterDataSourceConfiguration.Cache(path, maxDiskSizeInBytes);

    // Note that this will make the raster source already known to the passed map view.
    return RasterDataSource(mapView.getMapContext(),
            new RasterDataSourceConfiguration(dataSourceName, rasterProviderConfig, cacheConfig));
}

This code uses a tile source from Stamen Design, which can be used under the CC BY 3.0 license. The data itself comes from OpenStreetMap. For more information visit http://maps.stamen.com/#watercolor/12/37.7706/-122.3782.

Note that you can also use other tile sources that follow the OSM standard style format /zoom/x/y.png. The templateURL should look like this:

https://YourRasterTileService.com/{zoom}/{xTile}/{yTile}.png

Here, the zoom value represents the map's current zoom level, and xTile and yTile defines the horizontal and vertical tile numbers.

Once the tile source is created, a MapLayer can be built:

private MapLayer createMapLayer(String dataSourceName) {
    // The layer should be rendered on top of other layers.
    MapLayerPriority priority = new MapLayerPriorityBuilder().renderedLast().build();
    // And it should be visible for all zoom levels.
    MapLayerVisibilityRange range = new MapLayerVisibilityRange(0, 22 + 1);

    try {
        // Build and add the layer to the map.
        MapLayer mapLayer = new MapLayerBuilder()
                .forMap(mapView.getHereMap()) // mandatory parameter
                .withName(dataSourceName + "Layer") // mandatory parameter
                .withDataSource(dataSourceName, MapContentType.RASTER_IMAGE)
                .withPriority(priority)
                .withVisibilityRange(range)
                .build();
        return mapLayer;
    } catch (MapLayerBuilder.InstantiationException e) {
        throw new RuntimeException(e.getMessage());
    }
}

And finally, the MapTile's visibility can be controlled by enabling or disabling the layer. Note that we also need to provide a unique name. Each RasterDataSource can be created only once:

String dataSourceName = "myRasterDataSourceTonerStyle";
rasterDataSourceTonerStyle = createRasterDataSource(dataSourceName);
rasterMapLayerTonerStyle = createMapLayer(dataSourceName);

rasterMapLayerTonerStyle.setEnabled(true);

The resulting layer looks like this:

Screenshot: A b/w toner style map layer from Stamen Design shown on top of a map view.

The above screenshot shows that you can easily combine custom raster tiles with other HERE SDK features. For example, you can render several MapMarker instances on top of the tile data from a tile server.

Note

One of the main advantages of custom raster layers is that you can easily enhance the HERE map styles with a transparent custom tile source on top, for example, to show weather data or any other data you want to see on top of the map. When using an opaque raster tile source, it is recommended to combine this with an empty base map style.

If you do not use an empty base map style, then the underlying map scheme will "shine" through until the raster layer tiles are loaded. The accompanying example app shows how this looks like.

There are certain other parameters that you can adjust: For example, if your app uses multiple raster layers, you can define a load priority when building a layer with the MapLayerBuilder. This allows to specify an integer value: Higher values will lead to load the layer before layers with lower values. Note that this controls just the time when the layer is loaded, the MapLayerPriority controls how the layer is rendered: For example, renderedLast() means that the layer will be rendered on top of all other layers.

results matching ""

    No results matching ""