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

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

Related

How to display user location in reactive native maps and expo

I have the user's location but I can't seem to display it on the map, here's my code:
useEffect(() => {
(async () => {
let { status } = await Location.requestForegroundPermissionsAsync();
if (status !== 'granted') {
setErrorMsg('Permission to access location was denied');
return;
}
let location = await Location.getCurrentPositionAsync({});
setLocation(location);
})();
}, []);
let text = 'Waiting..';
if (errorMsg) {
text = errorMsg;
} else if (location) {
text = JSON.stringify(location);
}
let userLatitude = text.latitude
let userLongitude = text.longitude
return (
<View style={styles.layout}>
<MapView style={styles.map}>
<MapView.Marker
coordinate={{latitude: userLatitude,
longitude: userLongitude}}
title={"title"}
description={"description"}
/>
</MapView>
</View>
);
I got most of my code off of the expo location documentation, so I don't know what I'm doing wrong.
There is nothing in these variables
let userLatitude = text.latitude // undefined
let userLongitude = text.longitude // undefined
Location.getCurrentPositionAsync() returns object:
Object {
"coords": Object {
"accuracy": 5,
"altitude": 0,
"altitudeAccuracy": -1,
"heading": -1,
"latitude": 47.0448,
"longitude": 37.976,
"speed": -1,
},
"timestamp": 1659337371953.4102,
}
Working code example:
export default function App() {
const [userLocation, setUerLocation] = useState(null);
useEffect(() => {
(async () => {
// ... persmissions check
const location = await Location.getCurrentPositionAsync();
setUerLocation(location);
})()
}, [])
return (
<View style={styles.container}>
<MapView style={{width: '100%', height: '100%'}}>
{userLocation && <Marker coordinate={userLocation.coords} />}
</MapView>
</View>
);
}
if you have the user's foreground permission, you can see the location of the user directly inside the MapView component. There is a showsUserLocation prop that defaults to false. Set that to true and it should show up (fingers crossed ;).
return (
<View style={styles.layout}>
<MapView style={styles.map}
showsUserLocation={true}
followsUserLocation={true}
>
// (markers, geojson etc go here)
</MapView>
</View>
);

React Native Maps. Google maps returns back to initial location unable to drag the map around

Unable to drag the map around, after using google auto complete to search for the location. The map is able to change to the location. However I am unable to drag the map around, its stuck to the center of the location that I searched.
MapContainer.js is used to render the map and componentdidmount is used to retrieve the coordinates of busstops which will be displayed as markers under the render below
import { View } from "react-native";
import MapInput from "./MapInput";
import { getLocation, geocodeLocationByName } from "./location-service";
import React, { Component } from "react";
import MapView, { Marker, StyleSheet } from "react-native-maps";
const MyMapView = (props) => {
return (
<MapView
style={{ flex: 1 }}
region={props.region}
showsUserLocation={true}
onRegionChange={(reg) => props.onRegionChange(reg)}
>
{props.busstopArray.map((item) => {
return (
<Marker
key={item.bus_stop_id}
coordinate={{
latitude: Number(item.latitude),
longitude: Number(item.longitude),
}}
title={item.name}
></Marker>
);
})}
</MapView>
);
};
class MapContainer extends React.Component {
state = {
region: {},
busstop: [], //busstop is an empty array, in which the JSON values will be added, to be used later in the code.
};
componentDidMount() {
this.getInitialState();
const requestOptions = {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ route_id: "1" }, { route_id: "2" }),
};
fetch(
"https://laravelsyd-fypfinalver.herokuapp.com/getBusStop",
requestOptions
)
.then((response) => response.json())
.then((data) => {
this.setState({ busstop: data });
});
}
getInitialState() {
getLocation().then((data) => {
//import locationservice
console.log(data); //prints out intial region coords
this.setState({
region: {
latitude: data.latitude,
longitude: data.longitude,
latitudeDelta: 0.003,
longitudeDelta: 0.003,
},
});
});
}
getCoordsFromName(loc) {
this.setState({
region: {
latitude: loc.lat,
longitude: loc.lng,
latitudeDelta: 0.003,
longitudeDelta: 0.003,
},
});
}
onMapRegionChange(region) {
this.setState({ region });
}
render() {
const bus_stop = [...this.state.busstop];
// console.log(bus_stop); //testing to see if can display the json objects and it can
return (
<View style={{ flex: 1 }}>
<View style={{ flex: 1 }}>
<MapInput notifyChange={(loc) => this.getCoordsFromName(loc)} />
</View>
{this.state.region["latitude"] ? (
<View style={{ flex: 1 }}>
<MyMapView
region={this.state.region}
onRegionChange={(reg) => this.onMapRegionChange(reg)}
busstopArray={bus_stop}
/>
</View>
) : null}
</View>
);
}
}
export default MapContainer;
you have to add draggable in Marker:
<Marker
draggable
coordinate={{
latitude: Number(this.state.location.latitude),
longitude: Number(this.state.location.longitude),
}}
onDragEnd={e =>
this.setState({location: e.nativeEvent.coordinate})
}
/>

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;

Draw polylines in Mapview based on the current location of the user?

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

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