Cluster Layer (Large Dataset & Interactive Zoom)
Location: src/screens/ClusterLayerScreen.tsx
Demonstrates client-side clustering and rendering of large datasets (e.g. 30,000 GeoJSON points) with stepped color/size badge styling and interactive tap-to-zoom into clusters using native expansion zoom queries.
Cluster source and layers
<GeoJSONSource
id="cluster-source"
ref={sourceRef}
data={pointsData}
cluster={true}
clusterRadius={60}
clusterMaxZoom={14}
onPress={handleSourcePress}
>
{/* Cluster Bubble Circles */}
<Layer
id="cluster-circles"
type="circle"
filter={['has', 'point_count']}
paint={{
'circle-color': [
'step',
['get', 'point_count'],
'#6366f1', // < 100 points
100,
'#3b82f6', // 100 - 499 points
500,
'#10b981', // 500 - 1999 points
2000,
'#ef4444', // >= 2000 points
],
'circle-radius': [
'step',
['get', 'point_count'],
18,
100,
24,
500,
30,
2000,
36,
],
'circle-stroke-width': 2.5,
'circle-stroke-color': '#ffffff',
}}
/>
{/* Cluster Count Label */}
<Layer
id="cluster-count-label"
type="symbol"
filter={['has', 'point_count']}
layout={{
'text-field': ['to-string', ['get', 'point_count']],
'text-size': 12,
'text-allow-overlap': true,
'text-ignore-placement': true,
}}
paint={{
'text-color': '#ffffff',
}}
/>
{/* Individual Unclustered Points */}
<Layer
id="unclustered-points"
type="circle"
filter={['!', ['has', 'point_count']]}
paint={{
'circle-color': '#007AFF',
'circle-radius': 6,
'circle-stroke-width': 1.5,
'circle-stroke-color': '#ffffff',
}}
/>
</GeoJSONSource>
See also: React Native Map SDK overview, Draw Shapes.