Draw a Polyline Route
This tutorial shows how to draw polyline routes on your MapMetrics Android map using both the annotation API and GeoJSON line layers.
Prerequisites
- Completed the Getting Started Guide
- A MapMetrics API key and style URL from the MapMetrics Portal
Using a GeoJSON Line Layer
The recommended approach — add a styled line from GeoJSON data:
kotlin
import android.graphics.Color
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import org.maplibre.android.camera.CameraPosition
import org.maplibre.android.camera.CameraUpdateFactory
import org.maplibre.android.geometry.LatLng
import org.maplibre.android.geometry.LatLngBounds
import org.maplibre.android.maps.MapView
import org.maplibre.android.maps.MapMetricsMap
import org.maplibre.android.maps.Style
import org.maplibre.android.style.layers.LineLayer
import org.maplibre.android.style.layers.PropertyFactory.*
import org.maplibre.android.style.sources.GeoJsonSource
import org.maplibre.geojson.Feature
import org.maplibre.geojson.FeatureCollection
import org.maplibre.geojson.LineString
import org.maplibre.geojson.Point
class PolylineActivity : AppCompatActivity() {
private lateinit var mapView: MapView
private lateinit var map: MapMetricsMap
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_map)
mapView = findViewById(R.id.mapView)
mapView.onCreate(savedInstanceState)
mapView.getMapAsync { mapMetricsMap ->
map = mapMetricsMap
map.setStyle(
Style.Builder().fromUri(
"https://gateway.mapmetrics.org/styles/YOUR_STYLE_ID?token=YOUR_API_KEY"
)
) { style ->
addRoute(style)
}
}
}
private fun addRoute(style: Style) {
// Define route points
val routePoints = listOf(
Point.fromLngLat(2.3522, 48.8566), // Paris
Point.fromLngLat(4.3517, 50.8503), // Brussels
Point.fromLngLat(4.9041, 52.3676), // Amsterdam
Point.fromLngLat(9.9937, 53.5511), // Hamburg
Point.fromLngLat(13.4050, 52.5200), // Berlin
)
// Create GeoJSON line feature
val lineString = LineString.fromLngLats(routePoints)
val feature = Feature.fromGeometry(lineString)
val featureCollection = FeatureCollection.fromFeature(feature)
// Add source
style.addSource(GeoJsonSource("route-source", featureCollection))
// Add line layer
style.addLayer(
LineLayer("route-layer", "route-source").withProperties(
lineColor(Color.parseColor("#4285F4")),
lineWidth(4f),
lineOpacity(0.8f)
)
)
// Fit camera to route
val bounds = LatLngBounds.Builder()
for (point in routePoints) {
bounds.include(LatLng(point.latitude(), point.longitude()))
}
map.easeCamera(
CameraUpdateFactory.newLatLngBounds(bounds.build(), 80),
1000
)
}
override fun onStart() { super.onStart(); mapView.onStart() }
override fun onResume() { super.onResume(); mapView.onResume() }
override fun onPause() { super.onPause(); mapView.onPause() }
override fun onStop() { super.onStop(); mapView.onStop() }
override fun onDestroy() { super.onDestroy(); mapView.onDestroy() }
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
mapView.onSaveInstanceState(outState)
}
}Styled Route with Markers at Stops
Add start/end markers along the route:
kotlin
private fun addStyledRoute(style: Style) {
val stops = listOf(
Pair(Point.fromLngLat(2.3522, 48.8566), "Paris"),
Pair(Point.fromLngLat(4.3517, 50.8503), "Brussels"),
Pair(Point.fromLngLat(4.9041, 52.3676), "Amsterdam"),
Pair(Point.fromLngLat(13.4050, 52.5200), "Berlin"),
)
val routePoints = stops.map { it.first }
// Line source and layer
val lineString = LineString.fromLngLats(routePoints)
style.addSource(GeoJsonSource("route-source", Feature.fromGeometry(lineString)))
style.addLayer(
LineLayer("route-layer", "route-source").withProperties(
lineColor(Color.parseColor("#FF6B35")),
lineWidth(5f),
lineOpacity(0.9f),
lineJoin("round")
)
)
// Add markers at each stop
for ((point, name) in stops) {
map.addMarker(
org.maplibre.android.annotations.MarkerOptions()
.position(LatLng(point.latitude(), point.longitude()))
.title(name)
)
}
}Dashed Line
Create a dashed polyline using lineDasharray:
kotlin
style.addLayer(
LineLayer("dashed-route", "route-source").withProperties(
lineColor(Color.parseColor("#333333")),
lineWidth(3f),
lineDasharray(arrayOf(2f, 1f)) // 2px dash, 1px gap
)
)Multiple Route Layers
Show different route options with different colors:
kotlin
private fun addMultipleRoutes(style: Style) {
// Route 1 — fastest
val fastRoute = listOf(
Point.fromLngLat(2.3522, 48.8566),
Point.fromLngLat(6.1296, 49.8153),
Point.fromLngLat(13.4050, 52.5200),
)
// Route 2 — scenic
val scenicRoute = listOf(
Point.fromLngLat(2.3522, 48.8566),
Point.fromLngLat(4.3517, 50.8503),
Point.fromLngLat(4.9041, 52.3676),
Point.fromLngLat(9.9937, 53.5511),
Point.fromLngLat(13.4050, 52.5200),
)
// Fast route — blue, thicker
style.addSource(
GeoJsonSource("fast-source",
Feature.fromGeometry(LineString.fromLngLats(fastRoute)))
)
style.addLayer(
LineLayer("fast-layer", "fast-source").withProperties(
lineColor(Color.parseColor("#4285F4")),
lineWidth(5f),
lineOpacity(0.9f)
)
)
// Scenic route — green, thinner
style.addSource(
GeoJsonSource("scenic-source",
Feature.fromGeometry(LineString.fromLngLats(scenicRoute)))
)
style.addLayer(
LineLayer("scenic-layer", "scenic-source").withProperties(
lineColor(Color.parseColor("#34A853")),
lineWidth(3f),
lineOpacity(0.7f)
)
)
}Line Layer Properties
| Property | Type | Description |
|---|---|---|
lineColor | Color | Line color |
lineWidth | Float | Width in pixels |
lineOpacity | Float | Transparency (0.0 - 1.0) |
lineJoin | String | "round", "bevel", "miter" |
lineCap | String | "round", "butt", "square" |
lineDasharray | Array | Dash and gap lengths |
Next Steps
- GeoJSON Guide — Working with GeoJSON data
- Data-Driven Lines — Style lines by properties
- Polygon Area — Draw filled shapes
Tip: For route lines that pass beneath map labels, use style.addLayerBelow(layer, "labelLayerId") to insert the line layer below the label layer in the rendering stack.