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

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

Related

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;

Manage LAT + LON as variables to get DISTANCE

I have working snack with my geolocation, lat + lon. I'm trying to add the getDistance and isPointInCircle functions, they both work until I want to substitute a point with myLAT + myLON.
With good help I've been recomended to declare "const { latitude, longitude } = this.state;" but I'm missing something because I still get errors. I tried putting the functions inside and outside "componentDidMount()" but I'm not able to make it work.
import geolib from "geolib";
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
latitude: null,
longitude: null,
speed: null,
error: null,
};
}
componentDidMount() {
this.watchId = navigator.geolocation.watchPosition(
(position) => {
const { latitude, longitude } = this.state;
this.setState({
latitude: position.coords.latitude,
longitude: position.coords.longitude,
speed: position.coords.speed,
error: null,
});
},
(error) => this.setState({ error: error.message }),
{ enableHighAccuracy: true, timeout: 20000, maximumAge: 0, distanceFilter: 1},
);
}
componentWillUnmount() {
navigator.geolocation.clearWatch(this.watchId);
}
render() {
return (
<View style={styles.container}>
<View style={{ flexGrow: 0.3, alignItems: 'center', justifyContent: 'center' }}>
<Text>GeoLib:: Distance: {DIST} meters</Text> //I'd like to put the DISTANCE here
{this.state.error ? <Text>Error: {this.state.error}</Text> : null}
</View>
);
}
}
let RADIUS = geolib.isPointInCircle(
{ latitude: latitude, longitude: longitude },
{latitude: 37.600530, longitude: -122.482629},
1000
);
let DIST = geolib.getDistance(
{ latitude: latitude, longitude: longitude },
{latitude: 37.600530, longitude: -122.482629}
);
if(RADIUS == true){
console.log("I am in Radius.");
}else{
console.log("I am NOT in Radius.");
}
To access values that are in state you need to use this.state.key. You are trying to access values from state without the proper notation. You are also just adding values outside of your component that rely on values inside your component, that is not going to work.
Here is how I would implement your component, this is just one of many different ways that your component could be refactored.
// other import statements eg React etc.
import geolib from 'geolib';
export default class App extends Component {
constructor (props) {
super(props);
this.state = {
latitude: null,
longitude: null,
speed: null,
distance: null,
radius: null,
error: null
};
}
componentDidMount () {
this.watchId = navigator.geolocation.watchPosition(
(position) => {
const { latitude, longitude, speed } = position.coords;
const center = { latitude: 37.600530, longitude: -122.482629 };
const { radius, distance } = this.calculateMeasurements(latitude, longitude, center);
this.setState({
latitude: latitude,
longitude: longitude,
speed: speed,
radius: radius,
distance: distance,
error: null
});
},
(error) => this.setState({ error: error.message }),
{ enableHighAccuracy: true, timeout: 20000, maximumAge: 0, distanceFilter: 1 }
);
}
componentWillUnmount () {
navigator.geolocation.clearWatch(this.watchId);
}
/*
* latitude: user's latitude
* longitude: user's longitude
* center: center of the circle eg: { latitude: 37.600530, longitude: -122.482629 }
* this function is now reusable you don't have to hard code the center coordinates
*/
calculateMeasurements = (latitude, longitude, center) => {
const radius = geolib.isPointInCircle(
{ latitude: latitude, longitude: longitude },
{ latitude: center.latitude, longitude: center.longitude },
1000
);
const distance = geolib.getDistance(
{ latitude: latitude, longitude: longitude },
{ latitude: center.latitude, longitude: center.longitude }
);
console.log(radius, distance);
return { radius, distance };
}
render () {
const { radius, distance } = this.state;
if (radius === true) {
console.log('I am in Radius.');
} else if (radius === null) {
console.log('Radius has not been calculated');
} else if (radius === false) {
console.log('I am NOT in Radius.');
}
return (
<View style={styles.container}>
<View style={{ flexGrow: 0.3, alignItems: 'center', justifyContent: 'center' }}>
<Text>GeoLib:: Distance: {distance !== null ? distance : 'unknown'} meters</Text>
{this.state.error ? <Text>Error: {this.state.error}</Text> : null}
</View>
</View>
);
}
}
Add radius and distance initial values to state
Remove getting the latitude and longitude values in the componentDidMount, they are null and you aren't using the values anywhere.
Deconstruct the latitude, longitude and speed from the position.coords. This saves you have to type position.coords.key every time you want to use a value from it.
Create a helper function calculateMeasurements, that will calculate the radius and distance values that you want. Call it in the componentDidMount using the coordinates that you have just found. Then save the radius and distance to the state in the componentDidMount
Update render so that it uses the values from the state.
Fix the missing </View> tag in the render
Remove the let RADIUS = ... and other calculations from the bottom as they are not valid in this place.

creating a data and pushing in to array and showing them in a map is not working correctly?

Problem:
I am creating react native app with Google map integration. This is how I have done It.
import React, { Component } from "react";
import { View, Text, StyleSheet, Dimensions } from "react-native";
import { MapView } from "expo";
import Marker from "./Marker";
class Parking extends Component {
static navigationOptions = {
title: "Parking",
headerStyle: {
backgroundColor: "#06153b"
},
headerTintColor: "#fff",
headerTitleStyle: {
color: "#ffff"
}
};
constructor(props) {
super(props);
this.state = {
focusedLocation: {
latitude: 0,
longitude: 0,
latitudeDelta: 0.0122,
longitudeDelta:
(Dimensions.get("window").width / Dimensions.get("window").height) *
0.0122
},
locationChosen: false,
placesList: []
};
}
componentDidMount() {
navigator.geolocation.getCurrentPosition(
pos => {
const coordsEvent = {
nativeEvent: {
coordinate: {
latitude: pos.coords.latitude,
longitude: pos.coords.longitude
}
}
};
this.pickLocationHandler(coordsEvent);
},
err => {
console.log(err);
alert("Fetching the Position failed");
}
);
}
pickLocationHandler = event => {
const coords = event.nativeEvent.coordinate;
let placesList = [];
let places = [];
this.map.animateToRegion({
...this.state.focusedLocation,
latitude: coords.latitude,
longitude: coords.longitude
});
const apikey = "My API key";
fetch(
"https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=" +
coords.latitude +
"," +
coords.longitude +
"&radius=500" +
"&type=parking" +
"&key=" +
apikey
)
.then(response => response.json())
.then(responseJson => {
if (responseJson) {
placesList = responseJson.results;
console.log(placesList);
placesList.map((el, index) => {
const place = {
title: el.name,
coordinates: {
latitude: el.geometry.location.lat,
longitude: el.geometry.location.lng
}
};
places[index] = place;
});
}
});
if (places) {
this.setState({ placesList: places });
console.log(places);
}
this.setState({ locationChosen: true });
};
render() {
let marker = null;
if (this.state.locationChosen) {
marker = <MapView.Marker coordinate={this.state.focusedLocation} />;
}
const places = this.state.placesList;
return (
<View style={styles.container}>
<MapView
initialRegion={this.state.focusedLocation}
showsUserLocation={true}
style={styles.map}
onPress={this.pickLocationHandler}
ref={ref => (this.map = ref)}
>
{places.map((place, index) => {
<MapView.Marker
coordinate={place.coordinates}
title={place.title}
/>;
})}
{marker}
</MapView>
</View>
);
}
}
export default Parking;
const styles = StyleSheet.create({
container: {
width: "100%",
alignItems: "center",
paddingBottom: 10,
paddingLeft: 10,
paddingRight: 10,
paddingTop: 10
// backgroundColor:"#192f6a"
},
map: {
height: "100%",
width: "100%"
},
button: {
margin: 8
}
});
But It is showing Nothing On the Map. When I console log the places Like this.
if (places) {
this.setState({ placesList: places });
console.log(places);
}
It shows an Empty array. If I console log the placesList inside the fetch it shows the results. Can Someone help me to solve this problem and To modify My code in order to show the markers for the places that I have got from the fetch result from google API in the map?. Thank You very Much!!.
I'm fairly new to all this but I would say a couple of things:
1 - You're declaring 'place' as a const const place = ... but you're also trying to update it within the map loop, so I'm guessing that won't work. Use var place = ... instead?
2 - Instead of places[index] = place, does places.push(place) work?

React Native Maps animate to bearing after initial render

I am trying to call a method on the map right after the component first renders. In this case this.map is undefined, but shouldn't it be set by the ref? How do I get a reference to the MapView in the componentDidMount method?
import React from 'react';
import { MapView } from 'expo';
export default class Map extends React.Component {
componentDidMount() {
this.map.animateToBearing(25)
}
render() {
return (
<MapView
ref={ref => { this.map = ref }}
style={{ flex: 1 }}
mapType="satellite"
initialRegion={{
latitude: 39.2741004,
longitude: -76.6502307,
latitudeDelta: 0.002,
longitudeDelta: 0.001,
}}
/>
);
}
}
Looking at this Github issue, you probably have to use onLayout instead of componentDidMount.
For example:
<MapView
ref={ref => { this.map = ref }}
onLayout={() => this.map.animateToBearing(25)}
....
/>
const [heading, setHeading] = useState(0);
const cameraView = {
center: {
latitude: lat,
longitude: lng,
},
pitch: 10,
heading: heading,
altitude: 1,
zoom: 15
};
let getHeading = () => {
Location.watchHeadingAsync(value => {
setHeading(value.magHeading)
});
};
useEffect(()=>{
initialLocation();
getHeading();
}, [])
By using watchHeadingAsync you can update the heading constantly.

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
}
}