Skip to content
This site is a preview of the main branch. The published documentation is at maplibre.org.

Add data to the map

To draw your own data, you add a source and at least one layer. A source holds data, such as points, lines, or shapes. A layer draws the data from one source in one way, for example as lines or circles. Declare both in the block that you pass to rememberMapState.

rememberGeoJsonSource loads GeoJSON from a URL. This example draws a hiking trail as a blue line with a white outline:

App.kt
val state = rememberMapState {
val trail =
rememberGeoJsonSource(
GeoJsonData.Uri("https://maplibre.org/maplibre-gl-js/docs/assets/hike.geojson")
)
LineLayer(
id = "trail-casing",
source = trail,
color = const(Color.White),
width = const(6.dp),
)
LineLayer(
id = "trail",
source = trail,
color = const(Color.Blue),
width = const(4.dp),
)
}
MaplibreMap(state = state)

Layers draw in the order you declare them, so the wide white line goes first and the blue line draws on top of it. Each layer needs an ID that no other layer in the map uses.

GeoJsonData also takes a GeoJSON string or a GeoJSON object that you build in Kotlin. When the data changes, pass a new value, and the map redraws the layers. To group many nearby points, see Cluster points. To respond when the user taps a feature, see Handle gestures and clicks.

Other sources load tiles from a server: rememberVectorTileSource for vector tiles and rememberRasterTileSource for image tiles. Show 3D buildings and relief uses elevation tiles, and Add images and icons places a single image.

Layer properties take expressions instead of plain values. An expression can compute a value for each feature or for the current zoom level. Here the line for the trail source from the first example gets wider as the user zooms in:

App.kt
val state = rememberMapState {
LineLayer(
id = "trail",
source = trail,
color = const(Color.Blue),
width =
interpolate(
type = exponential(1.5f),
input = zoom(),
10 to const(1.dp),
18 to const(12.dp),
),
)
}
MaplibreMap(state = state)

Expressions in Kotlin explains how to write them. The MapLibre Style Specification lists every layer type and property.

Your layers draw above the whole base style, so a line covers street names and place names. Anchor.Below puts layers lower in the stack. This example draws trail under all of the base style’s labels and icons, whatever the style names those layers:

Default
ParkHill StreetRiversideLabels, then trail
Anchor.Below
ParkHill StreetRiversideTrail, then labels
App.kt
val state = rememberMapState {
Anchor.Below({ it.type == "symbol" }) {
LineLayer(id = "trail", source = trail, color = const(Color.Blue), width = const(4.dp))
}
}
MaplibreMap(state = state)

The lambda receives a LayerSummary for each base style layer. Layers with the type symbol draw text and icons. To place your layers next to one layer that you know, pass its ID instead, such as Anchor.Above("road_motorway") { ... }. Anchor.Bottom draws your layers under the whole base style.

A base style already loads its own data. getBaseSource returns one of its sources by ID, so you can draw that data in another way. This example marks every point of interest in the OpenFreeMap tiles with a red circle:

App.kt
val baseSourceState =
rememberMapState(baseStyle = BaseStyle.Uri("https://tiles.openfreemap.org/styles/liberty")) {
val tiles = getBaseSource<VectorTileSource>(id = "openmaptiles")
if (tiles != null) {
CircleLayer(
id = "all-pois",
source = tiles,
sourceLayer = "poi",
color = const(Color.Red),
)
}
}
MaplibreMap(state = baseSourceState)

The source ID and the sourceLayer names come from the style. To find them, open the style’s JSON and look at its sources and at the source-layer of its layers.

When a property such as a color changes, the map fades from the old value to the new one. Pass TransitionOptions to set how long that takes for one property. Here the trail line turns red over half a second when selected becomes true:

App.kt
val state = rememberMapState {
LineLayer(
id = "trail",
source = trail,
color = const(if (selected) Color.Red else Color.Blue),
colorTransition = TransitionOptions(duration = 500.milliseconds),
)
}
MaplibreMap(state = state)

Each property that can fade has a parameter that ends in Transition, such as colorTransition for color.

Layer declares a layer of any type by name. Use it for a type that has no composable in this library, such as one that a MapLibre Native plugin adds. This example wraps the ngon type from MapLibre Native’s sample layer plugin in a composable, so the properties get Kotlin types:

NgonLayer.kt
@Composable
@MaplibreComposable
fun NgonLayer(
id: String,
source: Source,
corners: Expression<FloatValue> = const(6f),
radius: Expression<DpValue> = const(5.dp),
color: Expression<ColorValue> = const(Color.Black),
) {
Layer(id = id, type = "ngon", source = source) {
paint("ngon-corners", corners)
paint("ngon-radius", radius)
paint("ngon-color", color)
}
}

The map must support the layer type and its properties. LayerProperties lists the functions that set properties.