Draw polylines in Mapview based on the current location of the user? - react-native-maps

The app updates the user's location and whenever it updates, I want it to create a path(polyline) so the user can view the previous path they had been. How can I accomplish this? It should add a polyline whenever onRegionChange is called.
constructor(props) {
super(props);
this.state = {
latitude: null,
longitude: null,
error: null
};
}
componentDidMount() {
this.watchId = navigator.geolocation.watchPosition(
(position) => {
let region = {
latitude: position.coords.latitude,
longitude: position.coords.longitude,
latitudeDelta: 0.00922*1.5,
longitudeDelta: 0.00421*1.5
}
let coordinates = [
{latitude: position.coords.latitude, longitude: position.coords.longitude}
]
this.onRegionChange(region, region.latitude, region.longitude);
},
(error) => this.setState({ error: error.message }),
{ enableHighAccuracy: true, timeout: 20000, maximumAge: 1000, distanceFilter: 10 },
);
}
onRegionChange(region, lastLat, lastLong) {
this.setState({
mapRegion: region,
lastLat: lastLat || this.state.lastLat,
lastLong: lastLong || this.state.lastLong
});
}
componentWillUnmount() {
navigator.geolocation.clearWatch(this.watchId);
}
render() {
return (
<View style={styles.container}>
<MapView
style={styles.map}
region={this.state.mapRegion}
followUserLocation={true}
onRegionChange={this.onRegionChange.bind(this)}>
<MapView.Marker
coordinate={{
latitude: (this.state.lastLat) || -36.82339,
longitude: (this.state.lastLong) || -73.03569,
}}
title = {"You are here"}
description = {"Hi there!"}
/>
</MapView>
</View>
);
}

I managed to fix it by adding this code
constructor(props) {
...
this.state = {
latitude: null,
longitude: null,
error: null,
routeCoordinates: []
};
}
componentDidMount() {
this.watchId = navigator.geolocation.watchPosition(
(position) => {
...
const { routeCoordinates } = this.state
const positionLatLngs = pick(position.coords, ['latitude', 'longitude'])
this.setState({ routeCoordinates: routeCoordinates.concat(positionLatLngs) })
...
}
...
render() {
return (
<View style={styles.container}>
<MapView
...
onRegionChange={this.onRegionChange.bind(this)}>
<MapView.Polyline
coordinates = {this.state.routeCoordinates}
strokeColor = '#19B5FE'
strokeWidth = {5}
/>
...
</MapView>
</View>
);
}

Related

I need to get my current location using GPS programmatically in react native How can i achieve it?

I am using react native maps and geolocation. I have set my Latitude and Longitude to
const LATITUDE = 37.78825;
const LONGITUDE = -122.4324
when my application Launches and this.watchlocation function called. Latitude and Longitude changes to my current position and so a componentDidupdate works and message is sent to pubnub..But when I travel some distance. component Did update not called ..how much distance I suppose to travel to send a message again to PubNub. I am using expo ~37.0.3 and "react-native-maps": "0.27.1"
Here is the sample code to do so
MAP.js
import MapView, { Marker, AnimatedRegion } from 'react-native-maps';
import PubNub from "pubnub";
const { width, height } = Dimensions.get('window');
const ASPECT_RATIO = width / height;
const LATITUDE = 37.78825;
const LONGITUDE = -122.4324;
const LATITUDE_DELTA = 0.0922;
const LONGITUDE_DELTA = LATITUDE_DELTA * ASPECT_RATIO;
const pubnub = new PubNub({
subscribeKey: "demo",
publishKey: "demo",
uuid: "myUUIDv"
});
export default class Trackee extends React.Component {
constructor(props) {
super(props);
this.state = {
latitude: LATITUDE,
longitude: LONGITUDE,
coordinate: new AnimatedRegion({
latitude: LATITUDE,
longitude: LONGITUDE,
latitudeDelta: 0,
longitudeDelta: 0,
}),
};
}
componentDidMount() {
this.watchLocation();
}
componentDidUpdate(prevProps, prevState) {
if (this.state.latitude !== prevState.latitude) {
pubnub.publish({
message: {
latitude: this.state.latitude,
longitude: this.state.longitude,
},
channel: 'location',
});
}
}
componentWillUnmount() {
navigator.geolocation.clearWatch(this.watchID);
}
watchLocation = () => {
const { coordinate } = this.state;
this.watchID = navigator.geolocation.watchPosition(
position => {
const { latitude, longitude } = position.coords;
const newCoordinate = {
latitude,
longitude,
};
if (Platform.OS === 'android') {
if (this.marker) {
coordinate.timing(newCoordinate).start(); // 500 is the duration to animate the marker
}
} else {
coordinate.timing(newCoordinate).start();
}
this.setState({
latitude,
longitude,
});
},
error => console.log(error),
{
enableHighAccuracy: true,
timeout: 20000,
maximumAge: 1000,
distanceFilter: 0,
}
);
};
getMapRegion = () => ({
latitude: this.state.latitude,
longitude: this.state.longitude,
latitudeDelta: LATITUDE_DELTA,
longitudeDelta: LONGITUDE_DELTA,
});
render() {
return (
<SafeAreaView style={{ flex: 1 }}>
<View style={styles.container}>
<MapView style={styles.map} showUserLocation followUserLocation loadingEnabled region={this.getMapRegion()}>
<Marker.Animated
ref={marker => {
this.marker = marker;
}}
coordinate={this.state.coordinate}
/>
</MapView>
</View>
</SafeAreaView>
);
}
}
const styles = StyleSheet.create({
container: {
...StyleSheet.absoluteFillObject,
justifyContent: 'flex-end',
alignItems: 'center',
},
map: {
...StyleSheet.absoluteFillObject,
},
});
https://www.npmjs.com/package/react-native-get-location
you can try using this package to get current lat long dynamically

What changes should I make to add marker on the map?

This is what I implemented so far. I am unable to add a marker to the current location on the map. Although I am able to get the current location as well as coordinates using the function findCoordinates() But I am unable to display on the map. Please suggest me where I am wrong or what should I do?
Here is the code I am sharing with you. Please suggest me the better ways to do it.
Thanks in advance
export default class App extends React.Component {
state = {
mapRegion: null,
hasLocationPermissions: false,
locationResult: null,
location: null,
};
componentDidMount() {
this.getLocationAsync();
}
handleMapRegionChange = mapRegion => {
this.setState({ mapRegion });
};
async getLocationAsync () {
// permissions returns only for location permissions on iOS and under certain conditions, see Permissions.LOCATION
const { status, permissions } = await Permissions.askAsync(
Permissions.LOCATION
);
if (status === 'granted') {
this.setState({ hasLocationPermissions: true });
// let location = await Location.getCurrentPositionAsync({ enableHighAccuracy: true });
let location = await Location.getCurrentPositionAsync({});
this.setState({ locationResult: JSON.stringify(location) });
// Center the map on the location we just fetched.
this.setState({
mapRegion: {
latitude: location.coords.latitude,
longitude: location.coords.longitude,
latitudeDelta: 0.04,
longitudeDelta: 0.05,
},
});
} else {
alert('Location permission not granted');
}
};
findCoordinates = () => {
navigator.geolocation.getCurrentPosition(
position => {
const location = JSON.stringify(position);
this.setState({ location });
},
error => Alert.alert(error.message),
{ enableHighAccuracy: true, timeout: 20000, maximumAge: 1000 }
);
};
render() {
return (
<View style={styles.container}>
<MapView
style={styles.mapStyle}
region={this.state.mapRegion}
onRegionChange={this.handleMapRegionChange}
/>
<Ionicons style = {{paddingLeft: 0}} name = "md-locate" size = {30} color = "red"
onPress = {this.findCoordinates}
/>
<TouchableOpacity onPress={this.findCoordinates}>
<Text style={styles.welcome}>My Location</Text>
<Text>Location: {this.state.location}</Text>
</TouchableOpacity>
</View>
);
}
}
App.navigationOptions = {
title: 'Location',
headerStyle: {
backgroundColor: '#ff6666',
},
headerTintColor: '#fff',
headerTitleStyle: {
fontWeight: 'bold',
fontSize:20
},
};
import { Marker } from 'react-native-maps';
//you need to set the initial latitude and longitude
value with deltas and use the marker component from react-native-maps
<MapView
style={styles.mapStyle}
region={this.state.mapRegion}
onRegionChange={this.handleMapRegionChange}>
<Marker
coordinate={this.state.location}
title={marker.title}
description={marker.description}
/>
</MapView>
You could try below
findCoordinates = () => {
navigator.geolocation.getCurrentPosition(
position => {
this.setState({ location });
},
error => Alert.alert(error.message),
{ enableHighAccuracy: true, timeout: 20000, maximumAge: 1000 }
);
};
render() {
return (
<View style={styles.container}>
<MapView
style={styles.mapStyle}
region={this.state.mapRegion}
onRegionChange={this.handleMapRegionChange}
>
{this.state.location && (
<MapView.Marker
coordinate={this.state.location.coords} // <-- Pass coordinate { latitude: number, longitude: number }
/>
)}
</MapView>
</View>
)
}

App crashes when location permission is not enabled in phone settings

I have react native app where i'm fetching the current location from user.For that, i have to enable location permission from settings of my phone otherwise the app crashes although i have enabled permission in my AndroidManifest.xml. App doesn't even ask for the permission to use the location. But it works well in emulator. Here's the component where i'm trying to get the user location.
class LocationTrack extends React.Component {
constructor(props) {
super(props);
this.state = {
latitude1: null,
longitude1: null,
error:null,
latitude: 37.78825,
longitude: -122.4324,
routeCoordinates: [],
distanceTravelled: 0,
prevLatLng: {},
coordinate: new AnimatedRegion({
latitude: 37.78825,
longitude: -122.4324,
latitudeDelta: 0,
longitudeDelta: 0
})
};
this.reftrack = firebase.firestore().collection('jobTracking');
}
componentDidMount() {
const { coordinate } = this.state;
this.watchID = navigator.geolocation.watchPosition(
position => {
const { routeCoordinates, distanceTravelled } = this.state;
const { latitude, longitude, accuracy, altitude, heading, speed } = position.coords;
const newCoordinate = {
latitude,
longitude,
accuracy,
altitude,
heading,
speed
};
console.log({ newCoordinate });
this.reftrack.add({
newCoordinate: newCoordinate,
distance : distanceTravelled + this.calcDistance(newCoordinate)
}).then(function () {
console.log("new location set");
}).catch(function (error) {
console.error("Error setting document: ", error);
});
if (Platform.OS === "android") {
if (this.marker) {
this.marker._component.animateMarkerToCoordinate(
newCoordinate,
500
);
}
} else {
coordinate.timing(newCoordinate).start();
}
this.setState({
latitude,
longitude,
routeCoordinates: routeCoordinates.concat([newCoordinate]),
distanceTravelled:
distanceTravelled + this.calcDistance(newCoordinate),
prevLatLng: newCoordinate
});
},
error => console.log(error),
{
enableHighAccuracy: true,
timeout: 20000,
maximumAge: 1000,
distanceFilter: 10
}
);
}
async componentWillMount() {
try {
const granted = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
{
'title': 'Example App',
'message': 'Example App access to your location '
}
)
if (granted === PermissionsAndroid.RESULTS.GRANTED) {
console.log("You can use the location")
alert("You can use the location");
} else {
console.log("location permission denied")
alert("Location permission denied");
}
} catch (err) {
console.warn(err)
}
}
componentWillUnmount() {
navigator.geolocation.clearWatch(this.watchID);
}
getMapRegion = () => ({
latitude: this.state.latitude,
longitude: this.state.longitude,
latitudeDelta: LATITUDE_DELTA,
longitudeDelta: LONGITUDE_DELTA
});
calcDistance = newLatLng => {
const { prevLatLng } = this.state;
return haversine(prevLatLng, newLatLng) || 0;
};
render() {
return (
<View style={styles.container}>
<MapView
style={styles.map}
provider={PROVIDER_GOOGLE}
showUserLocation
followUserLocation
loadingEnabled
region={this.getMapRegion()}
>
<Polyline coordinates={this.state.routeCoordinates} strokeWidth={5} />
<Marker.Animated
ref={marker => {
this.marker = marker;
}}
coordinate={this.state.coordinate}
/>
</MapView>
<View style={styles.buttonContainer}>
<TouchableOpacity style={[styles.bubble, styles.button]}>
<Text style={styles.bottomBarContent}>
{parseFloat(this.state.distanceTravelled).toFixed(2)} km
</Text>
</TouchableOpacity>
</View>
</View>
);
}
}
export default LocationTrack;

Setting a limit to user panning in React Native Maps

I'm trying to limit how much a user can pan when using Mapview from React Native Maps. There is no reason for the user to pan outside of the city and, I believe that the more the use pans outside of the city - the more of my daily request allotment would be used.
I've tried using the Mapview method, setMapBoundaries() but, that doesn't seem to work. Does anyone know how I can control this?
export class MapOfHalifax extends React.Component {
constructor(args) {
super(args);
this.state = {
markers: this.props.markers,
latitude: null,
longitude: null,
error: null,
}
}
componentDidMount() {
this.map.setMapBoundaries(
northEast = {
latitude: 44.722476,
longitude: -63.554658,
},southWest = {
latitude: 44.600546,
longitude: -63.613286,
}
)
}
componentWillUnmount() {
navigator.geolocation.clearWatch(this.watchId);
navigator.geolocation.stopObserving();
}
toggleSelect(id) {
this.props.toggleMarkerState(id)
}
checkDistanceFromSignificantLocation(currentPosition) {
this.state.markers.map((marker, index) => {
const START = {
latitude: currentPosition.coords.latitude,
longitude: currentPosition.coords.longitude
}
const END = {
latitude: marker.latitude,
longitude: marker.longitude
}
if (haversine(START, END, { threshold: MAX_DISTANCE_FROM_LOCATION, unit: PREFERED_DISTANCE_UNIT })
&& (!this.props.markers[index].locationPassedBy)){
this.props.updatePassedByTime(index, moment.utc())
NotificationsAndroid.localNotification({
title: "Approaching:",
body: marker.name + "!"
});
} else if (haversine(START, END, { threshold: MAX_DISTANCE_FROM_LOCATION, unit: PREFERED_DISTANCE_UNIT })
&& (moment().diff(this.props.markers[index].locationPassedBy,'minutes') > 60)){
NotificationsAndroid.localNotification({
title: "Approaching:",
body: marker.name + "!"
});
}
});
}
render() {
return (
<View style={styles.container}>
<MapView
ref={ref => { this.map = ref; }}
showsUserLocation={true}
showsMyLocationButton={true}
style={styles.map}
initialRegion={{
latitude: LATITUDE,
longitude: LONGITUDE,
latitudeDelta: LATITUDE_DELTA,
longitudeDelta: LONGITUDE_DELTA,
}}>
{this.props.markers.map((marker, index) => {
return (<MapView.Marker
coordinate={{
latitude: parseFloat(marker.latitude),
longitude: parseFloat(marker.longitude)
}}
title={marker.name}
key={marker.id}
onPress={() => {
const marker = this.state.markers[index]
marker.mapMarkerIsSelected = !marker.mapMarkerIsSelected
this.setState({
markers: [
...this.state.markers.slice(0, index),
marker,
...this.state.markers.slice(index + 1)
]
})
this.props.toggleMarkerState(marker.id)
}}
pinColor={
marker.mapMarkerIsSelected ? '#3590ea' : '#f06f77'
}>
</MapView.Marker>)
})}
</MapView>
</View>
);
}
}

Get current location, latitude and longitude in ReactNative using react-native-maps

I am developing a map location. When I click in some particular place I get the latitude and longitude, but not the current location, latitude and longitude.
I don't know how to find out.
How can I get them and how can I put the marker at that position?
Here is my code:
class Maps extends React.Component {
constructor(props) {
super(props);
this.state = {
region: {
latitude: LATITUDE,
longitude: LONGITUDE,
latitudeDelta: LATITUDE_DELTA,
longitudeDelta: LONGITUDE_DELTA,
},
marker: {
latlng:{
latitude: null,
longitude: null,
latitudeDelta: LATITUDE_DELTA,
longitudeDelta: LONGITUDE_DELTA
}
}
}
}
componentDidMount() {
navigator.geolocation.getCurrentPosition (
(position) => { alert("value:" + position) },
(error) => { console.log(error) },
{
enableHighAccuracy: true,
timeout: 20000,
maximumAge: 10000
}
)
}
onMapPress(e) {
alert("coordinates:" + JSON.stringify(e.nativeEvent.coordinate))
this.setState({
marker: [{ coordinate: e.nativeEvent.coordinate }]
})
}
render() {
return (
<View style={styles.container}>
<View style={{flexGrow:1}}>
<MapView
ref="map"
provider={this.props.provider}
style={styles.map}
onPress={this.onMapPress.bind(this)}
provider = {PROVIDER_DEFAULT}
mapType="standard"
zoomEnabled={true}
pitchEnabled={true}
showsUserLocation={true}
followsUserLocation={true}
showsCompass={true}
showsBuildings={true}
showsTraffic={true}
showsIndoors={true}>
</MapView>
</View>
</View>
)
}
}
I did it following these steps using react-native#0.42.3 and react-native-maps#^0.13.1 and using react-native#0.44.0 and react-native-maps#^0.15.2 at the date:
Set a mapRegion object in the state, the last longitude and the last latitude as null:
state = {
mapRegion: null,
lastLat: null,
lastLong: null,
}
Then within your componentDidMount() function watch for each change in the current position:
componentDidMount() {
this.watchID = navigator.geolocation.watchPosition((position) => {
...
});
}
When there are changes update them in your this.state.mapRegion, passing the actual coords and the delta values (mine can be different to yours, so adapt them):
componentDidMount() {
this.watchID = navigator.geolocation.watchPosition((position) => {
// Create the object to update this.state.mapRegion through the onRegionChange function
let region = {
latitude: position.coords.latitude,
longitude: position.coords.longitude,
latitudeDelta: 0.00922*1.5,
longitudeDelta: 0.00421*1.5
}
this.onRegionChange(region, region.latitude, region.longitude);
}, (error)=>console.log(error));
}
Then you need the onRegionChange() function, that's being used to "set" new values to your elements within the componentDidMount() function:
onRegionChange(region, lastLat, lastLong) {
this.setState({
mapRegion: region,
// If there are no new values set the current ones
lastLat: lastLat || this.state.lastLat,
lastLong: lastLong || this.state.lastLong
});
}
Unmount the geolocation on componentWillUnmount():
componentWillUnmount() {
navigator.geolocation.clearWatch(this.watchID);
}
And render the MapView passing your current mapRegion object, the MapView.Marker inside of it is just to show you the current latitude and longitude when they change:
render() {
return (
<View style={{flex: 1}}>
<MapView
style={styles.map}
region={this.state.mapRegion}
showsUserLocation={true}
followUserLocation={true}
onRegionChange={this.onRegionChange.bind(this)}>
<MapView.Marker
coordinate={{
latitude: (this.state.lastLat + 0.00050) || -36.82339,
longitude: (this.state.lastLong + 0.00050) || -73.03569,
}}>
<View>
<Text style={{color: '#000'}}>
{ this.state.lastLong } / { this.state.lastLat }
</Text>
</View>
</MapView.Marker>
</MapView>
</View>
);
}
Add the StyleSheet.absoluteFillObject for your map in order to render it properly using the whole width and height of your device.
const styles = StyleSheet.create({
map: {
...StyleSheet.absoluteFillObject,
}
});
So for your onPress() function you could do something similar to the onRegionChange(), that's to get the actual coordinates and to set them:
onMapPress(e) {
let region = {
latitude: e.nativeEvent.coordinate.latitude,
longitude: e.nativeEvent.coordinate.longitude,
latitudeDelta: 0.00922*1.5,
longitudeDelta: 0.00421*1.5
}
this.onRegionChange(region, region.latitude, region.longitude);
}
Check the full code on expo.io (although react-native-maps isn't installed)
I suggest you to read this official documentation about geolocalisation: https://facebook.github.io/react-native/docs/geolocation.html
Then, with the current location, you can put that information into your state:
navigator.geolocation.getCurrentPosition((position) => {
this.setState({position: {longitude: position.longitude, latitude: position.latitude}});
}, (error) => {
alert(JSON.stringify(error))
}, {
enableHighAccuracy: true,
timeout: 20000,
maximumAge: 1000
});
You will be able next, in your render method, to compose your final view with a marker:
render() {
return (
<MapView ...>
<MapView.Marker
coordinate={this.state.position}
title="title"
description="description"
/>
</MapView>
)
}
Look for location permission using the following code:
try {
const granted = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION
)
if (granted === PermissionsAndroid.RESULTS.GRANTED) {
alert("You can use the location")
}
else {
alert("Location permission denied")
}
}
catch (err) {
console.warn(err)
}
Fetch the current location latitude and longitude using the following code:
this.watchID = navigator.geolocation.watchPosition((position) => {
let region = {
latitude: position.coords.latitude,
longitude: position.coords.longitude,
latitudeDelta: 0.00922*1.5,
longitudeDelta: 0.00421*1.5
}
}