i'm React-Native newbie
I have created a google map but i want when i open my app, it will show my location first. How can i do it ?
Here is my code
export default class GoogleMapApi extends Component {
state = {
mapRegion: null,
lastLat: null,
lastLong: 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
}
this.onRegionChange(region, region.latitude, region.longitude);
});
}
onRegionChange(region, lastLat, lastLong) {
this.setState({
mapRegion: region,
// If there are no new values set use the the current ones
lastLat: lastLat || this.state.lastLat,
lastLong: lastLong || this.state.lastLong
});
}
And
componentWillUnmount() {
navigator.geolocation.clearWatch(this.watchID);
}
onMapPress(e) {
console.log(e.nativeEvent.coordinate.longitude);
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);
}
render() {
return (
<View style={{flex: 1}}>
<MapView
style={styles.map}
region={this.state.mapRegion}
showsUserLocation={true}
followUserLocation={true}
onRegionChange={this.onRegionChange.bind(this)}
onPress={this.onMapPress.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>
);
}
}
To get your current location you can use GeoLocation library of react-native, the docs for that is here(geoLocation).
`static getCurrentPosition(geo_success, geo_error?, geo_options?)`
docs for above method avaible here.
You have to use this method to get your current location coordinates and use those coordinates to see your location in maps.
Related
I am doing a RN project using Geolocation to get the current location, but I don't know what's wrong in this.
Here is my code:
import React, { Component } from 'react';
// Import required component
import { SafeAreaView, StyleSheet, Text, Alert, TouchableOpacity, Image, View } from 'react-native';
import { request, PERMISSIONS } from 'react-native-permissions';
// Import vector icons
import Icon from 'react-native-vector-icons/FontAwesome';
import MapView, { PROVIDER_GOOGLE, Platform, Marker, Callout, Circle } from 'react-native-maps';
import coordinate from '../../api/binLocationData';
import Geolocation from '#react-native-community/geolocation';
export class Home extends Component {
componentDidMount() {
this.requestLocationPermission();
}
requestLocationPermission = async () => {
if (Platform.OS === 'IOS') {
var response = await request(PERMISSIONS.IOS.LOCATION_WHEN_IN_USE);
console.log('IOS: ' + response);
if (response === 'granted') {
this.locateCurrentPosition();
}
} else {
var response = await request(PERMISSIONS.ANDROID.LOCATION_WHEN_IN_USE);
console.log('Android: ' + response);
if (response === 'granted') {
this.locateCurrentPosition();
}
}
};
locateCurrentPosition = () => {
Geolocation.getCurrentPosition(
(position) => {
console.log(JSON.stringify(position));
let initialPosition = {
latitude: position.coords.latitude,
longitude: position.coords.longitude,
latitudeDelta: 0.05,
longitudeDelta: 0.05,
};
this.setState({ initialPosition });
},
(error) => Alert.alert(error.message),
{ enableHighAccuracy: true, timeout: 1000, maximumAge: 1000 },
);
};
render() {
return (
<SafeAreaView style={{ flex: 1 }}>
<View style={{ flex: 1 }}>
<MapView
provider={PROVIDER_GOOGLE}
ref={(map) => (this._map = map)}
showsUserLocation={true}
style={styles.maps}
initialRegion={this.state.initialPosition}
// initialRegion={{
// latitude: 16.0599,
// longitude: 108.2438,
// latitudeDelta: 0.05,
// longitudeDelta: 0.05,
// }}
>
<Circle
radius={1000}
center={{ latitude: 16.0599, longitude: 108.2438 }}
fillColor={'rgba(51,150,152,0.3)'}
/>
<Marker coordinate={{ latitude: 16.0599, longitude: 108.2438 }}>
<Callout>
<Text>Bin 1</Text>
</Callout>
{/* <Image source={require('./src/assets/icons/bin.png')} /> */}
</Marker>
{coordinate.map((marker) => (
<Marker
key={marker.id}
coordinate={{ latitude: marker.latitude, longitude: marker.longitude }}
title={marker.name}
/>
))}
</MapView>
</View>
</SafeAreaView>
);
}
}
const styles = StyleSheet.create({
maps: {
...StyleSheet.absoluteFillObject,
},
});
export default Home;
And the debugging show:
TypeError: null is not an object (evaluating 'this.state.initialPosition')
How can I fix it?
You forget to initialise state. You should add this to your class component:
constructor(props) {
this.state = {
latitude: 0,
longitude: 0,
latitudeDelta: 0,
longitudeDelta: 0,
};
}
This should works:
import React, { Component } from "react";
// Import required component
import {
SafeAreaView,
StyleSheet,
Text,
Alert,
TouchableOpacity,
Image,
View,
} from "react-native";
import { request, PERMISSIONS } from "react-native-permissions";
// Import vector icons
import Icon from "react-native-vector-icons/FontAwesome";
import MapView, {
PROVIDER_GOOGLE,
Platform,
Marker,
Callout,
Circle,
} from "react-native-maps";
import coordinate from "../../api/binLocationData";
import Geolocation from "#react-native-community/geolocation";
export class Home extends Component {
constructor(props) {
this.state = {
latitude: 0,
longitude: 0,
latitudeDelta: 0,
longitudeDelta: 0,
};
}
componentDidMount() {
this.requestLocationPermission();
}
requestLocationPermission = async () => {
if (Platform.OS === "IOS") {
var response = await request(PERMISSIONS.IOS.LOCATION_WHEN_IN_USE);
console.log("IOS: " + response);
if (response === "granted") {
this.locateCurrentPosition();
}
} else {
var response = await request(PERMISSIONS.ANDROID.LOCATION_WHEN_IN_USE);
console.log("Android: " + response);
if (response === "granted") {
this.locateCurrentPosition();
}
}
};
locateCurrentPosition = () => {
Geolocation.getCurrentPosition(
(position) => {
console.log(JSON.stringify(position));
let initialPosition = {
latitude: position.coords.latitude,
longitude: position.coords.longitude,
latitudeDelta: 0.05,
longitudeDelta: 0.05,
};
this.setState({
latitude: initialPosition.latitude,
longitude: initialPosition.longitude,
latitudeDelta: initialPosition.latitudeDelta,
longitudeDelta: initialPosition.longitudeDelta,
});
},
(error) => Alert.alert(error.message),
{ enableHighAccuracy: true, timeout: 1000, maximumAge: 1000 }
);
};
render() {
return (
<SafeAreaView style={{ flex: 1 }}>
<View style={{ flex: 1 }}>
<MapView
provider={PROVIDER_GOOGLE}
ref={(map) => (this._map = map)}
showsUserLocation={true}
style={styles.maps}
initialRegion={this.state.initialPosition}
// initialRegion={{
// latitude: 16.0599,
// longitude: 108.2438,
// latitudeDelta: 0.05,
// longitudeDelta: 0.05,
// }}
>
<Circle
radius={1000}
center={{ latitude: 16.0599, longitude: 108.2438 }}
fillColor={"rgba(51,150,152,0.3)"}
/>
<Marker coordinate={{ latitude: 16.0599, longitude: 108.2438 }}>
<Callout>
<Text>Bin 1</Text>
</Callout>
{/* <Image source={require('./src/assets/icons/bin.png')} /> */}
</Marker>
{coordinate.map((marker) => (
<Marker
key={marker.id}
coordinate={{
latitude: marker.latitude,
longitude: marker.longitude,
}}
title={marker.name}
/>
))}
</MapView>
</View>
</SafeAreaView>
);
}
}
const styles = StyleSheet.create({
maps: {
...StyleSheet.absoluteFillObject,
},
});
export default Home;
I have implemented this example where I can zoom in to the given coordinates by clicking on the button.
Below you can read what I aiming to implement and I couldn't:
First, I want to be able to read coordinates out of a dynamic array, I tried by putting the array in the state but it fails.
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 MARKERS = [
{
latitude: 42.637368,
longitude: 21.148682,
},
{
latitude: 42.604021,
longitude: 21.261292,
},
{
latitude: 42.500833,
longitude: 21.181641,
}
];
const DEFAULT_PADDING = { top: 60, right: 60, bottom: 60, left: 60 };
export default class map_of_patients extends React.Component {
constructor(){
this.state={}
}
fitAllMarkers() {
this.map.fitToCoordinates(MARKERS, {
edgePadding: DEFAULT_PADDING,
animated: true,
});
}
render() {
return (
<View style={styles.container}>
<MapView
ref={ref => {
this.map = ref;
}}
style={styles.map}
initialRegion={{
latitude: LATITUDE,
longitude: LONGITUDE,
latitudeDelta: LATITUDE_DELTA,
longitudeDelta: LONGITUDE_DELTA,
}}
>
{MARKERS.map((marker, i) => (
<Marker key={i} identifier={`id${i}`} coordinate={marker} />
))}
</MapView>
<View style={styles.buttonContainer}>
<TouchableOpacity
onPress={() => this.fitAllMarkers()}
style={[styles.bubble, styles.button]}
>
<Text>Fit All Markers</Text>
</TouchableOpacity>
</View>
</View>
);
}
}
Second I would like to call the function fitAllMarkers into coordinates on start, so I don't have to click somewhere to do it. I tried by calling in inside componentDidMount() but didn't work either.
Third, I would like to zoom in to the region by giving the coordinates from the dynamic array.
I managed to fix all the issues mentioned in the question by doing the following:
-To fit all markers on initialization of the map I did as #Marek Lisik suggested using onMapReady={this.fitAllMarkers.bind(this)}.
-And to read from a dynamic array I managed to pass the array beforehand to the state and by the time the map is initialized it already had some data.
Here is the entire code again with the changes:
constructor(props) {
super(props);
this.state = {
region: {
latitude: 42.65847,
longitude: 21.16070,
latitudeDelta: 0.500,
longitudeDelta: 0.500 * width / height,
},
MARKERS: [
{
latitude: 42.637368,
longitude: 21.148682,
description: "dfsdf",
title: "title"
},
{
latitude: 42.604021,
longitude: 21.261292,
description: "sdfsdf",
title: "title"
},
{
latitude: 42.500833,
longitude: 21.181641,
description: "sdfsdfds",
title: "title"
}
]
};
}
fitAllMarkers() {
this.map.fitToCoordinates(this.state.MARKERS, {
edgePadding: DEFAULT_PADDING,
animated: true,
});
}
render() {
return (
<View style={styles.container}>
<MapView
ref={ref => {
this.map = ref;
}}
style={styles.map}
initialRegion={this.state.region}
onMapReady={this.fitAllMarkers.bind(this)}
>
{this.state.MARKERS.map((marker, i) => (
<Marker key={i} identifier={`id${i}`} coordinate={marker}
description={marker.description}>
</Marker>
))}
</MapView>
<View style={styles.buttonContainer}>
<TouchableOpacity
onPress={() => this.fitAllMarkers()}
style={[styles.bubble, styles.button]}
>
<Text>Fit All Markers</Text>
</TouchableOpacity>
</View>
</View>
);
}
I created the map using react-native-maps.Now i need to get latitude & longitude as a text when click on map.
I tried this way but it gives an error"Can't find variable:coordinate".
export default class Location extends Component {
constructor(props) {
super(props);
this.state = {
markers: []
};
this.handlePress = this.handlePress.bind(this);
}
handlePress(e) {
this.setState({
markers: [
...this.state.markers,
{
coordinate: e.nativeEvent.coordinate,
key: coordinate,
color: randomColor()
}
]
});
console.log(e.nativeEvent);
}
render() {
return (
<MapView
style={styles.map}
initialRegion={{
latitude: 7.8731,
longitude: 80.7718,
latitudeDelta: 0.0922,
longitudeDelta: 0.0421
}}
onPress={e => this.handlePress(e)}
>
{this.state.markers.map(marker => (
<Marker
key={marker.key}
coordinate={marker.coordinate}
pinColor={marker.color}
>
<View style={styles.marker}>
<Text style={styles.text}>{marker.coordinate}</Text>
</View>
</Marker>
))}
</MapView>
);
}
}
How i fix it?
I solved it.
export default class Location extends Component {
constructor(props) {
super(props);
this.state = {
region: {
latitude: LATITUDE,
longitude: LONGITUDE,
latitudeDelta: LATITUDE_DELTA,
longitudeDelta: LONGITUDE_DELTA,
},
markers: {
coordinate: {
latitude: 4,
longitude: 4,
},
key: id,
color: randomColor(),
}
};
}
onMapPress(e) {
this.setState({
markers:
{
coordinate: e.nativeEvent.coordinate,
key: id++,
color: randomColor(),
},
});
SaveAddress=()=>{
console.log(JSON.stringify(this.state.markers[0].coordinate.latitude))
}
}
render() {
return (
<MapView
provider={this.props.provider}
style={styles.map}
initialRegion={this.state.region}
onPress={e => this.onMapPress(e)}
>
<Marker
key={this.state.markers.key}
coordinate={this.state.markers.coordinate}
pinColor={this.state.markers.color}
>
<View style={styles.marker}>
<Text style={styles.text}>
{JSON.stringify(this.state.markers.coordinate)}</Text>
</View>
</Marker>
</MapView>
);
}
}
Add an onPress event to the map. like below. It will return the coordinates of pressed location in the map.
onPress={ (event) => console.log(event.nativeEvent.coordinate) }
So the code will be,
<MapView style = {styles.map}
initialRegion = {{
latitude: 7.8731,
longitude: 80.7718,
latitudeDelta: 0.0922,
longitudeDelta: 0.0421, }}
onPress={ (event) => console.log(event.nativeEvent.coordinate) }
/>
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>
);
}
}
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
}
}