Custom Map Styles
The HERE SDK for Flutter 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 .normalDay
or .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.62. 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: /your_app/assets
. This folder also needs to be included into your pubspec.yaml
:
# The following section is specific to Flutter.
flutter:
# Here we store our custom map styles.
assets:
- assets/
The main style file always ends with *.scene.json
.
Load the style into a map scene as follows:
import 'dart:io';
import 'package:here_sdk/core.dart';
import 'package:here_sdk/mapview.dart';
...
void loadCustomMapStyle() {
String filePath = loadCustomStyle('omv-traffic-traffic-normal-night.scene.json');
loadCustomStyle('omv-traffic-traffic-normal-night.jss');
loadCustomStyle('omv-traffic-traffic-normal-night-MapOmvVisibilityRanges.json');
loadCustomStyle('omv-traffic-traffic-normal-night-layer.properties.json');
_hereMapController.mapScene.loadSceneFromConfigurationFile(filePath, (MapError? error) {
if (error == null) {
} else {
print("Map scene not loaded. MapError: " + error.toString());
}
});
}
String loadCustomStyle(String assetFile) {
File file = File("assets/" + assetFile);
return file.path;
}
With the main *.scene.json
file the HERE SDK will find the other referenced style files - as exported from the editor, so we only need to get the file path for this file, but we have to make sure that all style files are kept together at the same folder level.
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.
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.rasterImage
.
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:
RasterDataSource _createRasterDataSource(String dataSourceName) {
String templateUrl = "https://stamen-tiles.a.ssl.fastly.net/toner/{z}/{x}/{y}.png";
List<int> storageLevels = [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
RasterDataSourceProviderConfiguration rasterProviderConfig =
RasterDataSourceProviderConfiguration.withDefaults(templateUrl, TilingScheme.quadTreeMercator, storageLevels);
String path = "cache/raster/toner";
int maxDiskSizeInBytes = 1024 * 1024 * 32;
RasterDataSourceCacheConfiguration cacheConfig = RasterDataSourceCacheConfiguration(path, maxDiskSizeInBytes);
return RasterDataSource(_hereMapController.mapContext,
RasterDataSourceConfiguration.withDefaults(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:
MapLayer _createMapLayer(String dataSourceName) {
MapLayerPriority priority = MapLayerPriorityBuilder().renderedLast().build();
MapLayerVisibilityRange range = MapLayerVisibilityRange(0, 22 + 1);
try {
MapLayer mapLayer = MapLayerBuilder()
.forMap(_hereMapController.hereMapControllerCore)
.withName(dataSourceName + "Layer")
.withDataSource(dataSourceName, MapContentType.rasterImage)
.withPriority(priority)
.withVisibilityRange(range)
.build();
return mapLayer;
} on MapLayerBuilderInstantiationException {
throw Exception("MapLayer creation failed.");
}
}
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.