Custom Map Styles
The HERE SDK for Android provides two flexible solutions to customize the map:
- Custom map styles that can be created using a dedicated WYSIWYG editor.
- Custom raster layers that can be loaded on top of map styles from external sources.
If you are looking for predefined map styles, see the Quick Start guide for an introduction: The HERE SDK comes already with 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 written in the YAML markup format. Such files can be generated with a WYSIWYG map style editor provided by HERE. For login, please use your HERE credentials (AccessKeyId
/ AccessKeySecret
).
Screenshot: Customize your map with HERE's online map style editor.
The following example shows a simple map style that defines how to render a water layer provided by the HERE Vector Tile API. For more details on the available layers within the Vector Tile API, please refer to the Layers
section of the Vector Tile API documentation.
sources:
omv:
type: OMV
scene:
background:
color: 'rgb(255, 255, 255)'
layers:
water_areas:
data:
source: omv
layer: water
draw:
polygons:
order: 1
color: 'rgb(153, 206, 255)'
The map style above defines the map scene's background color and a style named water_areas
that describes how to render the OMV data from the Vector Tile API's water
layer.
You can paste this custom map style into the map style editor and tweak it as much as you like.
As soon as you are satisfied, save the YAML map style description in a text file. Then add it via Xcode's Project navigator as file. Make sure to adapt the path to your Bundle
resources and load the file into a map scene as follows:
let bundle = Bundle(for: ViewController.self)
let yamlResourceUrl = bundle.url(forResource: "myCustomMapStyle",
withExtension: "yaml",
subdirectory: "MyData/style")
guard let yamlResourceString = yamlResourceUrl?.absoluteString else {
print("Error: Map style not found!")
return
}
mapView.mapScene.loadScene(pathToMapStyle: yamlResourceString, callback: self.onLoadScene)
Then implement the optional callback to know if loading the scene has succeeded:
func onLoadScene(errorCode: MapSceneLite.ErrorCode?) {
if let error = errorCode {
print("Error: New map scene not loaded: \(error)")
}
}
The screenshot below shows how the example YAML map style from above looks on a device.
Screenshot: The map after loading a custom map style configuration showing only water.
Using the custom map styles can be very effective to differentiate your app from other map applications. Besides, it is possible to change map styles on-the-fly, for example, to shift the user's attention on certain map elements based on the current state of your app. Keep in mind that enabling too many layers might cause performance drawbacks. In the same way, you can use adapted map styles to improve performance on low-end devices, for example, by disabling extruded buildings.
Note
For more information on how to create custom map styles, refer to the online documentation available from within the map style editor.
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.
The format of the URL should be as follows: https://YourRasterTileService.com/zoom/xTile/yTile.png
.
Here, the zoom
number represents the map's current zoom level, and xTile
and yTile
defines the horizontal and vertical tile numbers - as described in the OSM standard style.
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.
Below you can find an example on how to load a custom raster layer on top of a map style:
var mapSceneConfig = MapSceneConfigLite()
let myCustomRasterLayerName = "my_custom_raster_layer"
let staticTileServerProvider = SimpleTileServerProviderLite(url: "https://a.tile.openstreetmap.org/{z}/{x}/{y}.png")
let rasterLayer = RasterLayerLite(layerName: myCustomRasterLayerName,
maxZoom: 19,
drawOrder: 1000,
tileServerProvider: staticTileServerProvider)
mapSceneConfig.rasterLayers.append(rasterLayer)
mapSceneConfig.customMapLayers[myCustomRasterLayerName] = LayerStateLite.enabled
mapView.mapScene.loadScene(mapStyle: MapStyleLite.empty, sceneConfig: mapSceneConfig, callback: self.onLoadScene)
SimpleTileServerProviderLite
conforms to the TileServerProviderLite
protocol. You can provide your own implementation if you want to switch the provider at runtime. For example, with this you can use different raster layer sources based on the region in the world. SimpleTileServerProviderLite
is a convenience implementation that sets a static provider.
As a next step, implement the optional callback to know if loading the scene has succeeded:
func onLoadScene(errorCode: MapSceneLite.ErrorCode?) {
if let error = errorCode {
print("Error: New map scene not loaded: \(error)")
}
}
Above we use the German fork of OpenStreetMap's standard tile layer as RasterLayerLite
which supports zoom levels from 0 to 19. We can also specify the draw order. For that, we simply choose the default value that is used by most HERE SDK map items. By setting a draw order, you can specify if the raster layer should be shown below or above other map items. When choosing the default value of 1000, the raster layer will be drawn on top of the default map styles.
For the example above, we selected MapStyleLite.empty
since the OpenStreetMap tiles are fully opaque - and we don't want to load any other map data while panning. MapStyleLite.empty
simply consists of an empty YAML map style file.
Please note that onLoadScene() will not receive an error if the URL contains syntax errors or cannot be reached - the first tiles will start loading after the callback is completed and the custom raster layer will be added to the list of known layers. If the custom service does not host tile bitmaps for a certain combination of zoom level and tile numbers, no custom raster tile will be rendered and the specified MapStyleLite
will be visible again.
Note
One of the main advantages of custom raster layers is that you can easily enhance the HERE map styles with a custom tile source on top, for example, to show weather data or any other data you want to see on top of the map. With transparent tiles, this works better. When using an opaque raster tile source, it is recommended to combine this with a raster based map style or an empty map style - as shown in the example above.
Once the scene is loaded, you can control the visibility of the custom raster layer with the following code (here we hide the layer):
try? mapView.mapScene.setLayerState(layerName: myCustomRasterLayerName, newState: .disabled)
Setting a new layer state is performed synchronously, but it requires a valid map scene that must have been loaded before. Also, setting a new layer state while a new map scene is being loaded, may result in an error.
By setting a new layer state you can also enable other MapLayerLite
overlays on top of a map style. For example, you can enable a map layer to indicate realtime traffic flows. An example for this can be found in the Traffic section.
Note
Before using a custom tile server in your own app, please make sure to follow the applicable terms & conditions for the tile service of your choice.
Screenshot: Raster tiles from OpenStreetMap.org together with HERE map markers.
The above screenshot shows that you can easily combine custom raster tiles with other HERE SDK features. For this example, we render several map markers on top of the tile data from the OpenStreetMap tile server.