Skip to main content

Query Terrain Elevation

This is a fairly complex example demonstrating the use of AnimatedShape, Camera animation, queryTerrainElevation and AnimatedMarkerView

import React, { useState, useEffect, useRef } from 'react';
import { Easing, Button, View, Text } from 'react-native';
import length from '@turf/length';
import { lineString } from '@turf/helpers';
import { Animated as RNAnimated } from 'react-native';
import {
MapView,
SkyLayer,
Camera,
Logger,
Terrain,
RasterDemSource,
Animated,
AnimatedShape,
AnimatedRouteCoordinatesArray,
AnimatedExtractCoordinateFromArray,
MarkerView,
Atmosphere,
} from '@rnmapbox/maps';

Logger.setLogLevel('verbose');

const AnimatedMarkerView = RNAnimated.createAnimatedComponent(MarkerView);

const styles = {
mapView: { flex: 1 },
triangleStyle: (size, color) => ({
width: 0,
height: 0,
backgroundColor: 'transparent',
// @ts-ignore - borderStyle type issue
borderStyle: 'solid',
borderLeftWidth: size,
borderRightWidth: size,
borderTopWidth: size * 1.3,
borderLeftColor: 'transparent',
borderRightColor: 'transparent',
borderTopColor: color,
}),
};

const QueryTerrainElevation = () => {
let [animatedRoute, setAnimatedRoute] = useState(null);
let [actPoint, setActPoint] = useState(null);
let camera = useRef();
let [altitude, setAltitude] = useState(null);
let updateAltitudeInterval = useRef();
let map = useRef();
useEffect(() => {
return () => {
clearInterval(updateAltitudeInterval.current);
updateAltitudeInterval.current = null;
};
}, []);

function startAnimation(routeToAnimate) {
const ts = lineString(routeToAnimate.__getValue());
const total = length(ts, { units: 'meters' });
const points = routeToAnimate.__getValue();
const endPoint = points[points.length - 1];

routeToAnimate
.timing({
toValue: { end: { point: endPoint, from: total } },
duration: 20000,
easing: Easing.linear,
})
.start(() => {
clearInterval(updateAltitudeInterval.current);
updateAltitudeInterval.current = null;
});

camera.current.setCamera({
heading: 60,
zoomLevel: 13.5,
animationDuration: 20000,
});

updateAltitudeInterval.current = setInterval(async () => {
setAltitude(
Math.floor(
await map.current.queryTerrainElevation(actPoint.__getValue()),
),
);
}, 2000);
}

useEffect(() => {
(async () => {
let response = await fetch(
'https://docs.mapbox.com/mapbox-gl-js/assets/route-pin.geojson',
);
let featureCollection = await response.json();

let pinRoute = featureCollection.features[0].geometry.coordinates;

let animatedPinRoute = new AnimatedRouteCoordinatesArray(pinRoute, {
end: {
from: length(lineString(pinRoute)),
},
});
setAnimatedRoute(animatedPinRoute);
setActPoint(new AnimatedExtractCoordinateFromArray(animatedPinRoute, -1));
})();
}, []);
return (
<>
<Button title="Start" onPress={() => startAnimation(animatedRoute)} />
<MapView
style={styles.mapView}
styleURL={'mapbox://styles/mapbox/satellite-streets-v11'}
ref={map}
>
<Camera
centerCoordinate={[6.58968, 45.39701]}
zoomLevel={12.3}
heading={162}
pitch={76}
ref={camera}
/>

<RasterDemSource
id="mapbox-dem"
url="mapbox://mapbox.terrain-rgb"
tileSize={512}
maxZoomLevel={14}
>
<SkyLayer
id="sky-layer"
style={{
skyType: 'atmosphere',
skyAtmosphereColor: 'rgba(85, 151, 210, 0.5)',
}}
/>

<Terrain style={{ exaggeration: 1.5 }} />
<Atmosphere
style={{
starIntensity: 1.0,
range: [-0.7, 2.0],
spaceColor: '#def',
color: '#def',
highColor: '#def',
}}
/>
</RasterDemSource>

{animatedRoute && (
<Animated.ShapeSource
id="animated-route"
shape={
new AnimatedShape({
type: 'LineString',
coordinates: animatedRoute,
})
}
>
<Animated.LineLayer
id={'animated-route'}
style={{
lineColor: 'rgba(255,0,0,255)',
lineWidth: 3,
lineCap: 'round',
lineJoin: 'round',
}}
/>
</Animated.ShapeSource>
)}

{actPoint && (
<Animated.ShapeSource
id="currentLocationSource"
shape={
new AnimatedShape({
type: 'Point',
coordinates: actPoint,
})
}
>
<Animated.CircleLayer
id="currentLocationCircle"
style={{
circleOpacity: 1.0,
circleColor: '#c62221',
circleRadius: 6,
}}
/>
</Animated.ShapeSource>
)}
{actPoint && altitude && (
<AnimatedMarkerView coordinate={actPoint} anchor={{ x: 0.5, y: 1 }}>
<View style={{ alignItems: 'center' }}>
<View
style={{
backgroundColor: 'white',
padding: 10,
width: 140,
height: 50,
borderRadius: 10,
}}
>
<Text>Altitude: {altitude} m</Text>
</View>
<View
// @ts-ignore - borderStyle type issue in dynamic styles
style={[styles.triangleStyle(12, 'white'), { marginTop: -1 }]}
/>
</View>
</AnimatedMarkerView>
)}
</MapView>
</>
);
};

export default QueryTerrainElevation;


QueryTerrainElevation.png}