React Native Mapbox (rnmapbox/maps v10) Usage
Ajmal Hasan
Posted on October 18, 2022
MapView, Camera, PointAnnotation, ShapeSource, MarkerView, SymbolLayer, and LineLayer are components in the React Native Mapbox library that allow you to display maps and add markers, annotations, and other features to them.
Here's a brief overview of each component:
MapView: This component is the main component used to display a map. It provides various props for controlling the map's appearance and behavior.
Camera: This component is used to control the map's camera position and zoom level. It can be used to animate the camera to a specific location or zoom level.
PointAnnotation: This component is used to add a marker to the map. You can customize the marker's appearance and add a callout that appears when the user taps on the marker.
ShapeSource: This component is used to add a shape to the map, such as a polygon or line. You can customize the appearance of the shape and add data to it.
MarkerView: This component is used to create a custom marker for the PointAnnotation component. It allows you to use an image or a custom component as the marker.
SymbolLayer: This component is used to add symbols to the map, such as icons or text. You can customize the appearance of the symbols and add data to them.
LineLayer: This component is used to add lines to the map. You can customize the appearance of the lines and add data to them.
In summary, these components provide a way to display maps and add various features to them in a React Native app using the Mapbox library.
The below code explains how to use ShapeSource, MarkerView, SymbolLayer in Mapbox.
INSTALLATION:
USAGE:
Sample Data:(Note: geojson data only)
polygons.js
{
"type": "FeatureCollection",
"name": "GeoJsonData",
"features": [
{
"type": "Feature",
"properties": {
"description": null,
},
"geometry": {
"type": "MultiPolygon",
"coordinates": [
[
[
[46.6973896223821, 24.7938909593501],
[46.69730684623009, 24.79405349682493],
[46.69722194475514, 24.79401653642232],
[46.69730416732871, 24.79385517629931],
[46.6973896223821, 24.7938909593501]
]
]
]
}
},
*
*
*
]}
markers.js
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [
36.53387,
28.41464
]
},
"properties": {
"name_ar": "تبوك",
"name_en": "Tabuk",
"avail":"A"
}
},
*
*
*
]
}
Mapbox.js
import MapboxGL, {Camera} from '@rnmapbox/maps';
import {MAP_BOX_ACCESS_TOKEN} from '../../utils/constants/constants';
import * as turf from '@turf/turf';
import PolygonsGEOJSON from './polygons.json';
import MarkersGEOJSON from './markers.json';
MapboxGL.setAccessToken(MAP_BOX_ACCESS_TOKEN);
const MapBoxSRP = ({navigation, route}) => {
let _map = useRef(null);
const camera = useRef(null);
const dispatch = useDispatch();
const [localKmlData, setLocalKmlData] = useState(null);
const [isSateliteStyle, setSateliteStyle] = useState(true);
const [selectedDist, setSelectedDist] = useState();
const defaultCamera = {
centerCoordinate: [46.6254765922189, 24.942461593578678],
zoomLevel: 8,
};
//mapbox components style
const style_MB = {
polygonBG: {
fillColor: COLOR_PURPLE_100_OPACITY,
},
polygonBorder: {
lineColor: COLOR_WHITE,
lineWidth: 1,
},
countStyle: {
circleStrokeColor: COLOR_WHITE,
textField: ['get', 'point_count'],
iconImage: IMAGES.CIRCLE_GRADIENT,
textColor: COLOR_WHITE,
textFont: ['Open Sans SemiBold'],
},
dotMarkerStyle: {
circleRadius: 4,
circleStrokeWidth: 1,
circleStrokeColor: COLOR_WHITE,
},
calloutMarkerStyle: {
iconImage: IMAGES.MAP_POINTER,
textField: '22',
iconTextFit: 'both',
iconTextFitPadding: [5, 5, 5, 5],
textSize: 16,
iconAllowOverlap: true,
textAllowOverlap: true,
textColor: COLOR_BLACK,
textFont: ['Open Sans SemiBold'],
textOffset: [0, -1],
},
deselectText: {
textColor: COLOR_WHITE,
textHaloColor: COLOR_BLACK,
textHaloWidth: 1,
},
selectedPolygonBG: {
fillColor: COLOR_SECONDARY_DISABLE_OPACITY,
},
selectedPolygonBorder: {
lineColor: COLOR_WHITE,
lineWidth: 3,
},
};
//on screen load move view to the collection of all polygons without cropping any polygon
useEffect(() => {
try {
setTimeout(() => {
if (Object.keys(PolygonsGEOJSON).length > 0) {
let bboxPolygon = turf.bbox(PolygonsGEOJSON);
let minCoor = [bboxPolygon[0], bboxPolygon[1]];
let maxCoor = [bboxPolygon[2], bboxPolygon[3]];
console.log('onMapLoad', bboxPolygon);
camera?.current?.fitBounds(minCoor, maxCoor, [50, 20], 100);
setLocalKmlData(PolygonsGEOJSON);
}
}, 1000);
} catch ({message}) {
console.log('onMapLoadERROR', message);
}
}, []);
//focus the view to the selected polygon with bound
const onPressPolygon = e => {
const feature = e?.features[0];
console.log('onPressPolygon', feature);
var bboxPolygon = turf.bbox(feature);
let minCoor = [bboxPolygon[0], bboxPolygon[1]];
let maxCoor = [bboxPolygon[2], bboxPolygon[3]];
camera?.current?.fitBounds(minCoor, maxCoor, 20, 2000);
setSelectedDist(feature);
};
const setMapTypeFunc = () => {
setSateliteStyle(v => !v);
};
const SelectedPolygon = () =>
selectedDist ? (
<MapboxGL.ShapeSource id="selectedNYC" shape={selectedDist}>
<MapboxGL.FillLayer
sourceID="selectedNYC"
id="nycSelectedFillRed"
style={style_MB.selectedPolygonBG}
/>
<MapboxGL.LineLayer
sourceID="selectedNYC"
id="nycFillLine2"
style={style_MB.selectedPolygonBorder}
/>
</MapboxGL.ShapeSource>
) : null;
const SelectedPolygonProperties = () => (
<MapboxGL.ShapeSource
id="nyc1"
shape={Cities}
cluster={true}
// clusterProperties={{
// sum: [
// ['+', ['accumulated'], ['get', 'sum']],
// ['get', 'count'],
// ],
// }}
onPress={items => {
onPressPolygon(items);
}}>
<MapboxGL.CircleLayer
sourceID="nyc1"
id="dot"
style={style_MB.dotMarkerStyle}
// minZoomLevel={14}
/>
<MapboxGL.SymbolLayer
sourceID="nyc1"
id="callout"
style={{
...style_MB.calloutMarkerStyle,
textField: '{name_en}',
}}
minZoomLevel={10}
/>
{/* <MapboxGL.SymbolLayer
filter={['has', 'point_count']}
sourceID="nyc1"
id="countCluster"
style={style_MB.countStyle}
maxZoomLevel={14}
/> */}
</MapboxGL.ShapeSource>
);
//Custom Marker
const RenderAnnotationsProperties = () => {
return selectedPolygonPropeties?.features.map((v, i) => (
<MapboxGL.MarkerView
key={i}
id="pointAnnotation"
// allowOverlap={true}
coordinate={v?.geometry?.coordinates}>
<TouchableOpacity onPress={() => setselectedMarkerId(i)}>
<View
style={{
padding: 10,
backgroundColor: selectedMarkerId === i ? COLOR_RED : COLOR_WHITE,
}}>
<Text style={{textColor: COLOR_BLACK}}>
{v?.properties?.conversionUnit +
' ' +
v?.properties?.conversionPrice}
</Text>
</View>
<View style={styles.dotProp} />
</TouchableOpacity>
</MapboxGL.MarkerView>
));
};
return (
<View style={styles.page}>
<View style={styles.container}>
<MapboxGL.MapView
ref={_map}
onPress={onPressMapView}
// onDidFinishLoadingMap={onMapLoad}
style={styles.map}
styleURL={
!isSateliteStyle
? MapboxGL.StyleURL.Satellite
: MapboxGL.StyleURL.Street
}
localizeLabels={locale: I18nManager.isRTL ? 'ar' : 'en'}
attributionEnabled={false}
compassEnabled={true}
logoEnabled={false}
scaleBarEnabled={isIOS() ? true : false}
>
<Camera
maxBounds={{
ne: [60.54, 41.5],
sw: [32.05, 9.77],
}}
ref={camera}
maxZoomLevel={20}
minZoomLevel={4}
centerCoordinate={[46.67, 24.71]}
/>
{!localKmlData ? null : (
<>
<MapboxGL.ShapeSource
id="nyc"
// url={localKmlData}
shape={localKmlData}
onPress={items => {
onPressPolygon(items);
}}>
<MapboxGL.FillLayer
id="nycFill"
style={style_MB.polygonBG}
filter={['!=', 'avail', 'A']} //show non-sold items, avail will be present in properties attribute of geojson
/>
<MapboxGL.LineLayer
sourceID="nyc"
id="nycFillLine"
style={style_MB.polygonBorder}
/>
</MapboxGL.ShapeSource>
<SelectedPolygon />
<SelectedPolygonProperties />
{selectedPolygonPropeties ? (
<RenderAnnotationsProperties />
) : null}
</>
)}
</MapboxGL.MapView>
</View>
<TouchableOpacity
style={styles.mapType(isSateliteStyle)}
onPress={setMapTypeFunc}>
<CustomIcon
color={!isSateliteStyle ? COLOR_GRAY_70 : COLOR_SECONDARY}
name={ICONOGRAPHY.FLOORS}
size={20}
/>
</TouchableOpacity>
</View>
);
};
export default MapBoxSRP;
Posted on October 18, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.