Setting a limit to user panning in React Native Maps - react-native

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

Related

TypeError: null is not an object (evaluating 'this.state.initialPosition') - React Native

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;

How to get coordinates when placed the marker on map

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

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

Show my location in map react-native

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.

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