Shapes
Drawing lines
Draw routes and paths using GeoJSON LineString.
import { Camera, LineLayer, MapView, MarkerView, ShapeSource } from '@maplibre/maplibre-react-native';
import type { FeatureCollection } from 'geojson';
import React from 'react';
import { ActivityIndicator, StyleSheet, Text, View } from 'react-native';
import { BARIKOI_COLORS, MAP_STYLES, useBarikoiMapStyle } from '../utils/mapUtils';
export default function LineScreen() {
const { styleJson, loading, error } = useBarikoiMapStyle();
const lineGeoJSON: FeatureCollection = {
type: 'FeatureCollection',
features: [{
type: 'Feature',
properties: {},
geometry: {
type: 'LineString',
coordinates: [
[90.364159, 23.823724],
[90.369159, 23.825724],
],
},
}],
};
if (loading) return <View style={styles.centered}><ActivityIndicator size="large" color={BARIKOI_COLORS.primary} /></View>;
if (error) return <View style={styles.centered}><Text>{error}</Text></View>;
return (
<View style={styles.container}>
<MapView style={styles.map} attributionEnabled={false} zoomEnabled compassEnabled mapStyle={styleJson}>
<Camera centerCoordinate={[90.366659, 23.824724]} zoomLevel={15} animationMode="linearTo" />
<ShapeSource id="lineSource" shape={lineGeoJSON}>
<LineLayer id="lineLayer" style={MAP_STYLES.line} />
</ShapeSource>
<MarkerView coordinate={[90.364159, 23.823724]} anchor={{ x: 0.5, y: 1.0 }}>
<View style={styles.dot} />
</MarkerView>
<MarkerView coordinate={[90.369159, 23.825724]} anchor={{ x: 0.5, y: 1.0 }}>
<View style={styles.dot} />
</MarkerView>
</MapView>
</View>
);
}
const styles = StyleSheet.create({
container: { flex: 1, backgroundColor: 'white' },
map: { flex: 1 },
centered: { flex: 1, justifyContent: 'center', alignItems: 'center' },
dot: { width: 14, height: 14, borderRadius: 7, backgroundColor: BARIKOI_COLORS.primary },
});
Line style properties:
| Property | Type | Description |
|---|---|---|
lineColor | string | Color (e.g. '#2e8555') |
lineWidth | number | Width in pixels |
lineCap | "butt" | "round" | "square" | End cap style |
lineJoin | "bevel" | "round" | "miter" | Join style |
lineDasharray | number[] | e.g. [2, 2] for dashed lines |
Drawing polygons
Render filled areas using GeoJSON Polygon.
Close the ring
The first and last coordinate of a polygon ring must be identical. If they don't match, the polygon will not render.
import { Camera, FillLayer, LineLayer, MapView, MarkerView, ShapeSource } from '@maplibre/maplibre-react-native';
import React from 'react';
import { ActivityIndicator, StyleSheet, Text, View } from 'react-native';
import { BARIKOI_COLORS, MAP_STYLES, useBarikoiMapStyle } from '../utils/mapUtils';
export default function PolygonScreen() {
const { styleJson, loading, error } = useBarikoiMapStyle();
const polygonGeoJSON = {
type: 'FeatureCollection',
features: [{
type: 'Feature',
properties: {},
geometry: {
type: 'Polygon',
coordinates: [[
[90.364159, 23.823724],
[90.369159, 23.825724],
[90.367159, 23.820724],
[90.364159, 23.823724], // must equal first point
]],
},
}],
};
const vertices = [[90.364159, 23.823724], [90.369159, 23.825724], [90.367159, 23.820724]];
if (loading) return <View style={styles.centered}><ActivityIndicator size="large" color={BARIKOI_COLORS.primary} /></View>;
if (error) return <View style={styles.centered}><Text>{error}</Text></View>;
return (
<View style={styles.container}>
<MapView style={styles.map} attributionEnabled={false} zoomEnabled compassEnabled mapStyle={styleJson}>
<Camera centerCoordinate={[90.366659, 23.823724]} zoomLevel={15} animationMode="linearTo" />
<ShapeSource id="polygonSource" shape={polygonGeoJSON}>
<FillLayer id="polygonFill" style={MAP_STYLES.polygon} />
{/* Add a LineLayer for a thicker outline */}
<LineLayer id="polygonOutline" style={{ lineColor: '#2e8555', lineWidth: 3 }} />
</ShapeSource>
{vertices.map((coord, i) => (
<MarkerView key={i} coordinate={coord} anchor={{ x: 0.5, y: 1.0 }}>
<View style={styles.dot} />
</MarkerView>
))}
</MapView>
</View>
);
}
const styles = StyleSheet.create({
container: { flex: 1, backgroundColor: 'white' },
map: { flex: 1 },
centered: { flex: 1, justifyContent: 'center', alignItems: 'center' },
dot: { width: 14, height: 14, borderRadius: 7, backgroundColor: BARIKOI_COLORS.primary },
});
Polygon fill properties:
| Property | Type | Description |
|---|---|---|
fillColor | string | Fill color (e.g. 'rgba(46, 133, 85, 0.5)') |
fillOutlineColor | string | Border color |
fillOpacity | number | Opacity 0–1 |
For a thicker outline, add a LineLayer after the FillLayer inside the same ShapeSource.
Circle polygons
MapLibre does not have a built-in circle shape. Use the createCirclePolygon utility from mapUtils.ts to approximate one with a many-sided polygon.
import { createCirclePolygon } from '../utils/mapUtils';
const circleCoords = createCirclePolygon([90.364159, 23.823724], 0.5); // 500m radius
const circleGeoJSON = {
type: 'FeatureCollection',
features: [{
type: 'Feature',
geometry: {
type: 'Polygon',
coordinates: [circleCoords], // wrap in array for the ring
},
}],
};
// Render with FillLayer
<ShapeSource id="circleSource" shape={circleGeoJSON}>
<FillLayer id="circleFill" style={MAP_STYLES.polygon} />
</ShapeSource>
createCirclePolygon parameters:
| Parameter | Type | Description |
|---|---|---|
center | [number, number] | [longitude, latitude] |
radiusInKm | number | Radius in kilometers (e.g. 0.5 for 500m) |
points | number | Vertex count, default 64 (higher = smoother) |
Combined geometry
Combine circles, lines, polygons, and markers on a single map. Each shape type uses its own ShapeSource and layer.
Unique IDs required
Every ShapeSource and layer must have a unique id across the entire map. Duplicate IDs will cause rendering errors.
import { Camera, FillLayer, LineLayer, MapView, MarkerView, ShapeSource } from '@maplibre/maplibre-react-native';
import type { FeatureCollection } from 'geojson';
import React from 'react';
import { ActivityIndicator, StyleSheet, Text, View } from 'react-native';
import { BARIKOI_COLORS, MAP_STYLES, createCirclePolygon, useBarikoiMapStyle } from '../utils/mapUtils';
export default function GeometryScreen() {
const { styleJson, loading, error } = useBarikoiMapStyle();
const center: [number, number] = [90.366659, 23.823724];
const circleGeoJSON: FeatureCollection = {
type: 'FeatureCollection',
features: [{ type: 'Feature', properties: {}, geometry: { type: 'Polygon', coordinates: [createCirclePolygon(center, 0.3)] } }],
};
const lineGeoJSON: FeatureCollection = {
type: 'FeatureCollection',
features: [{ type: 'Feature', properties: {}, geometry: { type: 'LineString', coordinates: [[90.364159, 23.823724], [90.369159, 23.825724]] } }],
};
const markerPoints = [[90.364159, 23.823724], [90.369159, 23.825724], center];
if (loading) return <View style={styles.centered}><ActivityIndicator size="large" color={BARIKOI_COLORS.primary} /></View>;
if (error) return <View style={styles.centered}><Text>{error}</Text></View>;
return (
<View style={styles.container}>
<MapView style={styles.map} attributionEnabled={false} zoomEnabled compassEnabled mapStyle={styleJson}>
<Camera centerCoordinate={center} zoomLevel={15} animationMode="linearTo" />
<ShapeSource id="circleSource" shape={circleGeoJSON}>
<FillLayer id="circleFill" style={MAP_STYLES.polygon} />
</ShapeSource>
<ShapeSource id="lineSource" shape={lineGeoJSON}>
<LineLayer id="lineLayer" style={MAP_STYLES.line} />
</ShapeSource>
{markerPoints.map((coord, i) => (
<MarkerView key={i} coordinate={coord} anchor={{ x: 0.5, y: 1.0 }}>
<View style={styles.dot} />
</MarkerView>
))}
</MapView>
</View>
);
}
const styles = StyleSheet.create({
container: { flex: 1, backgroundColor: 'white' },
map: { flex: 1 },
centered: { flex: 1, justifyContent: 'center', alignItems: 'center' },
dot: { width: 14, height: 14, borderRadius: 7, backgroundColor: BARIKOI_COLORS.primary },
});