Draw a Polygon Area
This tutorial shows how to draw filled polygon shapes on your MapMetrics Android map — useful for highlighting zones, districts, or geofences.
Prerequisites
- Completed the Getting Started Guide
- A MapMetrics API key and style URL from the MapMetrics Portal
Basic Polygon with Fill
Add a filled polygon using a GeoJSON source and fill layer:
kotlin
import android.graphics.Color
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import org.maplibre.android.camera.CameraPosition
import org.maplibre.android.geometry.LatLng
import org.maplibre.android.maps.MapView
import org.maplibre.android.maps.MapMetricsMap
import org.maplibre.android.maps.Style
import org.maplibre.android.style.layers.FillLayer
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.Point
import org.maplibre.geojson.Polygon
class PolygonActivity : 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 ->
addPolygon(style)
}
}
}
private fun addPolygon(style: Style) {
// Define polygon vertices (must form a closed ring)
val polygonPoints = listOf(
listOf(
Point.fromLngLat(2.3200, 48.8700),
Point.fromLngLat(2.3800, 48.8700),
Point.fromLngLat(2.3800, 48.8400),
Point.fromLngLat(2.3200, 48.8400),
Point.fromLngLat(2.3200, 48.8700) // Close the ring
)
)
val polygon = Polygon.fromLngLats(polygonPoints)
val feature = Feature.fromGeometry(polygon)
// Add GeoJSON source
style.addSource(GeoJsonSource("polygon-source", feature))
// Add fill layer
style.addLayer(
FillLayer("polygon-fill", "polygon-source").withProperties(
fillColor(Color.parseColor("#4285F4")),
fillOpacity(0.3f)
)
)
// Add outline layer
style.addLayer(
LineLayer("polygon-outline", "polygon-source").withProperties(
lineColor(Color.parseColor("#4285F4")),
lineWidth(2f),
lineOpacity(0.8f)
)
)
// Center camera on polygon
map.cameraPosition = CameraPosition.Builder()
.target(LatLng(48.855, 2.350))
.zoom(13.0)
.build()
}
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)
}
}Multiple Colored Zones
Display several zones with different colors:
kotlin
private fun addMultipleZones(style: Style) {
data class Zone(
val id: String,
val points: List<Point>,
val color: String,
val name: String
)
val zones = listOf(
Zone(
"zone-a",
listOf(
Point.fromLngLat(2.32, 48.87),
Point.fromLngLat(2.35, 48.87),
Point.fromLngLat(2.35, 48.855),
Point.fromLngLat(2.32, 48.855),
Point.fromLngLat(2.32, 48.87),
),
"#FF6B35", "District A"
),
Zone(
"zone-b",
listOf(
Point.fromLngLat(2.35, 48.87),
Point.fromLngLat(2.38, 48.87),
Point.fromLngLat(2.38, 48.855),
Point.fromLngLat(2.35, 48.855),
Point.fromLngLat(2.35, 48.87),
),
"#34A853", "District B"
),
Zone(
"zone-c",
listOf(
Point.fromLngLat(2.32, 48.855),
Point.fromLngLat(2.38, 48.855),
Point.fromLngLat(2.38, 48.84),
Point.fromLngLat(2.32, 48.84),
Point.fromLngLat(2.32, 48.855),
),
"#9C27B0", "District C"
),
)
for (zone in zones) {
val polygon = Polygon.fromLngLats(listOf(zone.points))
val feature = Feature.fromGeometry(polygon)
style.addSource(GeoJsonSource("${zone.id}-source", feature))
style.addLayer(
FillLayer("${zone.id}-fill", "${zone.id}-source").withProperties(
fillColor(Color.parseColor(zone.color)),
fillOpacity(0.3f)
)
)
style.addLayer(
LineLayer("${zone.id}-outline", "${zone.id}-source").withProperties(
lineColor(Color.parseColor(zone.color)),
lineWidth(2f)
)
)
}
}Clickable Polygon
Show info when the user taps inside a polygon:
kotlin
private fun addClickablePolygon(style: Style) {
addPolygon(style) // Add polygon first
map.addOnMapClickListener { latLng ->
// Query the polygon layer at the tap point
val screenPoint = map.projection.toScreenLocation(latLng)
val features = map.queryRenderedFeatures(screenPoint, "polygon-fill")
if (features.isNotEmpty()) {
android.widget.Toast.makeText(
this,
"Tapped inside polygon!",
android.widget.Toast.LENGTH_SHORT
).show()
}
true
}
}Fill Layer Properties
| Property | Type | Description |
|---|---|---|
fillColor | Color/Expression | Fill color |
fillOpacity | Float | Fill transparency (0.0 - 1.0) |
fillOutlineColor | Color | Border color (1px only) |
fillAntialias | Boolean | Smooth edges (default: true) |
Next Steps
- GeoJSON Guide — Load polygons from GeoJSON files
- Data-Driven Styling — Color polygons by data properties
- Building Layer — 3D extruded polygons
Tip: Always close polygon rings — the first and last point must be identical. For outlines thicker than 1px, add a separate LineLayer on top of the FillLayer as shown above.