how to make the react native map camera animated with the movement of the marker but must be at the same time
i use react-native-maps with google maps onn android
and i eant the camera map animated withe the marker moves at the same time
buut alwways the marker moves then the map follow so there is a delay between the map and marker also i want the marker to bhe on the buttom of the screen always
animate_point for animate the camera using clous coordinate and animate_point_GPS using gps coordinate
this is the Map Component
export default function MapUI() {
const { authData } = useContext(AuthContext);
const { gpsStatus, setGPSStatus } = useContext(AuthContext);
const { mapLayer, setMapLayer } = useContext(AuthContext);
const { positiveRCM, setPositiveRCM } = useContext(AuthContext);
const [token, setToken] = useState();
const [loading, setLoading] = useState(true);
const [coordinate, setCoordinate] = useState(null);
const mapRef = useRef(null);
const [markersMeasurement, setMarkersMeasurement] = useState([]);
const [prevDirection, setPrevDirection] = useState(null); // State to store previous direction
const navigation = useNavigation();
const { height } = Dimensions.get("window");
/**
* connectWebSocketApi
*/
useEffect(() => {
connectWebSocketApi(authData.ClientPrefix);
}, []);
// WebSocket event handler
const onMessage = (event) => {
try {
const data = JSON.parse(event.data);
if (data.type === "coordinate" && data.device == authData.DeviceID) {
// Update coordinate state with the received data
if (!gpsStatus) {
Updatecoordinate(
data?.latitude,
data?.longitude,
data?.azimuth,
data?.speed
);
}
}
} catch (error) {
console.error("Error parsing WebSocket data:", error);
}
};
/**
* control the permission
*/
useEffect(() => {
setToken(authData.TOKEN);
setGPSStatus(gpsStatus);
setMapLayer(mapLayer);
setPositiveRCM(positiveRCM);
}, []);
/**
* control the switch between GPS and cloud
*/
useEffect(() => {
// Wait for a short delay before checking gpsStatus
const timeoutId = setTimeout(() => {
if (gpsStatus) {
getLocation(); //getLocation()
} else {
getCoordinates();
}
}, 500); // Adjust the delay time as needed
// Clean up the timeout to avoid memory leaks
return () => clearTimeout(timeoutId);
}, [gpsStatus]);
/**
* control the switch between GPS and cloud
*/
useEffect(() => {
if (gpsStatus) {
const intervalId = setInterval(async () => {
try {
const location = await Location.getCurrentPositionAsync({
accuracy: Location.Accuracy.Highest,
});
Updatecoordinate_GPS(
location.coords?.latitude,
location.coords?.longitude,
location.coords?.heading,
location.coords?.speed
);
} catch (error) {
console.error("Error getting location:", error);
}
}, 800); // Update location every 1 second
return () => clearInterval(intervalId);
}
}, []);
/**
*
* @param {*} latitude
* @param {*} longitude
* @param {*} azimuth
*/
const Updatecoordinate_GPS = (latitude, longitude, azimuth, speed) => {
if (
latitude != coordinate?.latitude ||
longitude != coordinate?.longitude
) {
const newCoordinate = {
latitude,
longitude,
azimuth,
speed,
};
//console.log(newCoordinate)
setCoordinate(newCoordinate);
animate_point_GPS(newCoordinate);
}
};
/**
*
*/
const animate_point_GPS = async (newCoordinate) => {
let duration = 0;
const heading = newCoordinate?.azimuth;
const headingChanged = Math.abs(heading - prevDirection) > 10; // Define a threshold for significant change
headingChanged && setPrevDirection(heading); // Update previous direction
if (newCoordinate?.speed > 100) {
duration = 1100;
} else if (newCoordinate?.speed > 50) {
duration = 900;
} else {
duration = 1100;
}
// Animate camera to the new coordinates
mapRef?.current?.animateCamera(
{
heading: headingChanged ? heading : prevDirection,
center: {
latitude: newCoordinate.latitude,
longitude: newCoordinate.longitude,
},
pitch: 55,
},
{ duration: duration }
);
};
/**
* get current location using GPS
*/
const getLocation = async () => {
setLoading(true);
let { status } = await Location.requestForegroundPermissionsAsync();
if (status !== "granted") {
console.error("Permission to access location was denied");
return;
}
let location = await Location.getCurrentPositionAsync({
accuracy: Location.Accuracy.High,
});
const newCoordinate = {
latitude: location.coords.latitude,
longitude: location.coords.longitude,
azimuth: location.coords.heading,
};
setCoordinate(newCoordinate);
//console.log("location: ", location.coords)
setLoading(false);
};
/**
* get current location using
*/
/**
*
* @param {number} latitude
* @param {number} longitude import defaultPin from "/default.png"
* @param {number} azimuth
*/
const Updatecoordinate = (latitude, longitude, azimuth, speed) => {
const newCoordinate = {
latitude,
longitude,
};
setCoordinate(newCoordinate);
animate_point();
};
/**
* animate_point the camera to follow the device
*/
const animate_point = async () => {
let duration = 0;
const heading = gpsStatus ? coordinate?.heading : coordinate?.azimuth;
const headingThreshold = 10; // Define a threshold for significant heading changes
// Determine if the heading change is significant
const headingChanged =
prevDirection === null ||
Math.abs(heading - prevDirection) > headingThreshold;
if (headingChanged) {
setPrevDirection(heading); // Update previous direction only if change is significant
}
if (coordinate?.speed > 100) {
duration = 1100;
} else if (coordinate?.speed > 50) {
duration = 900;
} else {
duration = 1100;
}
mapRef?.current?.animateCamera(
{
// heading: headingChanged ? heading : prevDirection,
center: {
latitude: coordinate.latitude,
longitude: coordinate.longitude,
},
pitch: 55,
},
{ duration: duration }
);
};
return (
<>
<View style={styles_map.container}>
{/* WebSocket configuration component */}
<WebSocketConfig onMessage={onMessage} />
{coordinate && (
<>
<MapView
ref={mapRef}
provider={PROVIDER_GOOGLE}
style={{ ...StyleSheet.absoluteFillObject }}
initialRegion={{
latitude: coordinate?.latitude,
longitude: coordinate?.longitude,
latitudeDelta: 0.001,
longitudeDelta: 0.001,
}}
mapPadding={{ top: height * 0.9, left: 0, right: 0, bottom: 0 }}
rotateEnabled={false}
zoomEnabled={false}
zoomTapEnabled={false}
zoomControlEnabled={false}
toolbarEnabled={false}
showsCompass={false}
mapType={mapLayer}
>
<DeviceMarker
key={coordinate?.device}
coord={coordinate}
gpsStatus={gpsStatus}
mapRef={mapRef}
/>
</MapView>
</>
)}
<View>
</View>
<View style={styles_map.buttonContainer}>
</View>
</View>
</>
);
}
and this is DeviceMarker component
export default function DeviceMarker({ coord, gpsStatus, mapRef }) {
const [marker, setMarker] = useState(null);
const markerRef = useRef(null);
const duration = 1100;
const [tracksViewChanges, setTracksViewChanges] = useState(true);
const [coordinate, setCoordinate] = useState(
new AnimatedRegion({
latitude: coord?.latitude || 0, // Ensure default value is provided
longitude: coord?.longitude || 0, // Ensure default value is provided
latitudeDelta: 0.001,
longitudeDelta: 0.001,
})
);
useEffect(() => {
const timer = setTimeout(() => {
setTracksViewChanges(false);
detectHeadingAtFirstLoad();
}, 1000); // Adjust the delay as necessary
return () => clearTimeout(timer);
}, []);
useEffect(() => {
// Update marker position when coord changes
if (markerRef.current) {
const newCoordinate = {
latitude: coord?.latitude || 0, // Ensure default value is provided
longitude: coord?.longitude || 0, // Ensure default value is provided
latitudeDelta: 0.001,
longitudeDelta: 0.001,
};
coordinate
.timing({
...newCoordinate,
duration,
easing: Easing.linear,
useNativeDriver: false,
})
.start();
}
}, [coord]);
/**
* detectHeadingAtFirstLoad
*/
const detectHeadingAtFirstLoad = async () => {
const heading = gpsStatus ? coord?.heading : coord?.azimuth;
mapRef?.current?.animateCamera({
heading: heading,
center: {
latitude: coord.latitude,
longitude: coord.longitude,
},
pitch: 55,
});
};
return (
<Marker.Animated
ref={markerRef}
tracksViewChanges={tracksViewChanges}
tracksInfoWindowChanges={false}
coordinate={coordinate}
anchor={{ x: 0.5, y: 0.5 }}
>
<Image
style={{
height: 50,
width: 50,
transform: [
{
rotate: "0deg",
},
],
}}
source={require("../assets/icon.png")}
resizeMode="cover"
/>
</Marker.Animated>
);
}
please help me to figure this out
Thank you