ok so i have a page in react native that has a mapview and i am displaying the current location of the user and the destination of the user, at first the user's position on the map didn't move if the user moves, so i decided to use Location.watchPositionAsync
, this worked perfectly, but noticed that the path in which the user was to take to reach the destination was not following the path of the road because i was using Polyline
, so i change from that to MapViewDirections
, but this also came with its own issue, everything is working but the MapViewDirections
is always rerendering because the initial location is updating due to me using Location.watchPositionAsync
, if the initial longitude and latitude are not changing the stuff works fine, but once its start changing it gives the issue,
does anyone have an idea on how to fix this? my code is below:
import {
REACT_NATIVE_IMPORTS
} from "react-native";
import React, { REACT_IMPORTS } from "react";
import Modal from "react-native-modal";
import MapView, { Marker, Polyline } from "react-native-maps";
import { PROVIDER_GOOGLE } from "react-native-maps";
import Button from "../components/Button";
import { StatusBar } from "expo-status-bar";
import { GestureHandlerRootView } from "react-native-gesture-handler";
import BottomSheet, { BottomSheetRefProps } from "../components/BottomSheet";
import P from "../components/P";
import H1 from "../components/H1";
import { Ionicons, AntDesign } from "@expo/vector-icons";
import MapViewDirections from "react-native-maps-directions";
import CustomMarker from "../components/CustomMarker";
import { Distance } from "../Request-Handlers/Functions";
import * as Location from "expo-location";
import CustomMarker2 from "../components/CustomMarker2";
const { width, height } = Dimensions.get("window");
function calculateTime(
startLat: any,
startLng: any,
endLat: any,
endLng: any,
speed: any
) {
const earthRadius = 6371; // Earth's radius in kilometers
const distance = haversineDistance(
startLat,
startLng,
endLat,
endLng,
earthRadius
);
const timeInSeconds = distance / speed;
const timeInMinutes = Math.round(timeInSeconds / 60);
return timeInMinutes;
}
function haversineDistance(
lat1: any,
lon1: any,
lat2: any,
lon2: any,
radius: any
) {
const toRadians = (value: any) => (value * Math.PI) / 180;
const dLat = toRadians(lat2 - lat1);
const dLon = toRadians(lon2 - lon1);
const a =
Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(toRadians(lat1)) *
Math.cos(toRadians(lat2)) *
Math.sin(dLon / 2) *
Math.sin(dLon / 2);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
const distance = radius * c;
return distance;
}
export default function MapScreen({ route, navigation }: any) {
const ref = useRef<BottomSheetRefProps>(null);
const mapRef = useRef<MapView>(null);
const { items } = route.params;
const [isModalVisible, setModalVisible] = useState(false);
const [lat, setLat] = useState(48.8587741);
const [lon, setLon] = useState(2.2069771);
const [distance, setDistance] = useState(0);
const [locationFetched, setLocationFetched] = useState(false); // New state
const onPress = useCallback(() => {
const isActive = ref?.current?.isActive();
if (isActive) {
ref?.current?.scrollTo(0);
} else {
ref?.current?.scrollTo(-200);
}
}, []);
const pickup = async () => {
console.log(items.id);
setModalVisible(false);
navigation.navigate("ProffOfPickupScreen", { items: items });
};
const [location, setLocation] = useState({ latitude: 0, longitude: 0 });
const [destination, setDestination] = useState({ latitude: 0, longitude: 0 });
const [speed, setSpeed] = useState("");
useEffect(() => {
// Request permission to access the user's location
const requestLocationPermission = async () => {
const { status } = await Location.requestForegroundPermissionsAsync();
if (status !== "granted") {
console.log("Permission to access location was denied");
return;
}
// Start listening to location updates
Location.watchPositionAsync(
{
accuracy: Location.Accuracy.High,
timeInterval: 1000, // Update location every 1 second
distanceInterval: 2, // Update location if the device moves 2 meters
},
(location) => {
// @ts-ignore
setLocation(location.coords);
setLocationFetched(true);
let distance = Distance(
location.coords.latitude,
location.coords.longitude,
items.dropOffCoord.lat,
items.dropOffCoord.lng
);
let time = calculateTime(
location.coords.latitude,
location.coords.longitude,
items.dropOffCoord.lat,
items.dropOffCoord.lng,
0.011252
);
const hours = Math.floor(Number(time) / 60);
const remainingMinutes = Number(time) % 60;
setSpeed(`${hours}hr ${remainingMinutes}mins`);
setDistance(distance);
}
);
};
requestLocationPermission();
}, []);
useEffect(() => {
// Set the destination coordinates
setDestination({
latitude: items.pickUpCoord.lat,
longitude: items.pickUpCoord.lng,
}); // Replace with your desired destination coordinates
}, [location]);
return (
<GestureHandlerRootView style={{ flex: 1 }}>
<StatusBar style="dark" />
<View style={styles.container}>
{locationFetched && (
<MapView
style={styles.map}
provider={PROVIDER_GOOGLE}
initialRegion={{
// @ts-ignore
latitude: location.latitude,
// @ts-ignore
longitude: location.longitude,
latitudeDelta: 0.01,
longitudeDelta: 0.01,
}}>
<MapViewDirections
origin={{
latitude: location.latitude,
longitude: location.longitude,
}}
destination={{
latitude: items.pickUpCoord.lat,
longitude: items.pickUpCoord.lng,
}}
apikey="MY_API"
strokeWidth={4}
strokeColor="#111111"
/>
<CustomMarker coordinate={location} />
<CustomMarker2 coordinate={destination} distance={distance} />
{/* <Polyline
// @ts-ignore
coordinates={[location, destination]}
strokeWidth={4}
strokeColor="black"
/> */}
</MapView>
)}
<TouchableOpacity
style={{
width: (10 * width) / 100,
height: (10 * width) / 100,
backgroundColor: "#F1F3F9",
position: "absolute",
borderRadius: 100,
justifyContent: "center",
alignItems: "center",
top: "6%",
left: "5%",
}}
onPress={() => navigation.pop()}>
<AntDesign name="arrowleft" size={24} color="black" />
</TouchableOpacity>
<StatusBar style="light" />
<TouchableOpacity style={styles.button} onPress={onPress} />
<BottomSheet ref={ref}>
<View
style={{
flex: 1,
backgroundColor: "white",
}}>
<View
style={{
flexDirection: "row",
alignItems: "center",
paddingHorizontal: "5%",
}}>
<H1 style={{ marginRight: "2%" }}>{speed}</H1>
{/* <H1 style={{ marginRight: "2%" }}>1hr 40mins</H1> */}
<H1 style={{ marginRight: "2%", color: "gray" }}>
{"("}
{distance.toFixed(1)}km{")"}
</H1>
</View>
<P style={{ fontSize: (3 * width) / 100, marginLeft: "5%" }}>
You’re driving to the pickup address
</P>
<View
style={{
height: 1,
width: "100%",
backgroundColor: "#ddd",
marginTop: "5%",
}}></View>
<View
style={{
width: "97%",
paddingLeft: "3%",
}}>
<View style={styles.cardinside}>
<Ionicons name="location-sharp" size={20} color="gold" />
<P style={styles.upLeft1}>Est. Pick Up:</P>
<P style={styles.upRight}>{items.pickUpDate.split(" ")[1]}</P>
</View>
<View style={styles.cardinside1}>
<Ionicons name="location-sharp" size={20} color="#00000000" />
<P style={styles.downRight}>{items.dropoffLocation}</P>
</View>
</View>
<Button
Title="Mark as picked up"
type="warning"
full={true}
onPress={() => pickup()}
css={{ marginTop: "-1%" }}
/>
</View>
</BottomSheet>
</View>
</GestureHandlerRootView>
);
}
const styles = StyleSheet.create({
// MY_STYLES
});