how to set initial region with multiple markers react native - react-native

I have the following coordinates
const myLocation = {
latitude: 25.410776,
longitude: 68.275936
}
const routes = [
{
number: 13,
coordinates: {
latitude: 31.411533,
longitude: -81.281607,
}
},
{
number: 15,
coordinates: {
latitude: 18.16,
longitude: -67.038078,
}
},
]
I am trying to set the initial region according to these coordinates but it's not working. this is my code
<MapView
ref={mapView}
style={{ flex: 1 }}
provider={PROVIDER_GOOGLE}
initialRegion={{
latitude: myLocation.latitude +
routes.reduce((a, b) => a + (b.coordinates.latitude || 0), 0) / 2,
longitude: myLocation.longitude +
routes.reduce((a, b) => a + (b.coordinates.longitude || 0), 0) / 2,
latitudeDelta: Math.abs(
routes.reduce((a, b) => a + (b.coordinates.latitude || 0), 0) - myLocation.latitude) * 2,
longitudeDelta: Math.abs(
routes.reduce((a, b) => a + (b.coordinates.longitude || 0), 0) - myLocation.longitude) * 2,
}} >

Related

How to check lat or long value is in the MapView region

How to check the latitude and the longitude value is laying on the MapView region or outside the MapView region.
//This is outside render funtion
handleItem = (lat, lng) => {
this.setState({ latitude: lat, longitude: lng })
this.map.animateToCoordinate({ latitude: lat, longitude: lng }, 1000)
}
//this is is in render function
<MapView style={{ flex: 1 }}
ref={map => this.map = map}
initialRegion={{
latitude: this.state.latitude,
longitude: this.state.longitude,
latitudeDelta: 0.0922,
longitudeDelta: 0.0421,
}}>
<Marker coordinate={this.state} />
{ this.handleItem(this.state.latitude, this.state.longitude) }}
</MapView>

How to add title to Polygon using react-native-maps

I'm trying to draw specific polygons in MapView, but I'm not sure how to add title to Polygon.
I tried to search official documentation, but only Marker has title property, so I'm not sure if it's supported.
Marker can be used something like this
<Marker
coordinate={latittude: x, longitude: y}
title="I am Marker"
/>
so is it possible to add title property to Polygon like this:
<Polygon
coordinates=[{latittude: x, longitude: y},...]
title="I am Polygon"
/>
???Expecting something like this...
I don't think you have any other option but you can use marker which works pretty nice.
<MapView.Marker key={`${key}Marker`} coordinate={center} anchor={centerAnchor} tracksViewChanges={false}>
<Text key={`${key}Text`} style={styles.clusterText}>
{data.properties.n}
</Text>
</MapView.Marker>
don't forget the tracksViewChanges={false} or the map will go crazy for many markers and put a huge load on the cpu
I also encountered the same problem, I know this is late but here's what I did. I also didn't know if react native maps have that method right now. So for alternative, I used Marker as title. And used this function from github to get the center of polygon.
center_polygon(coordinates) {
let x = coordinates.map(c => c.latitude);
let y = coordinates.map(c => c.longitude);
let minX = Math.min.apply(null, x);
let maxX = Math.max.apply(null, x);
let minY = Math.min.apply(null, y);
let maxY = Math.max.apply(null, y);
return {
latitude: (minX + maxX) / 2,
longitude: (minY + maxY) / 2
};
}
Polygon
return (
<View>
<Marker
coordinate={polygon_center}
>
<Text note style={{color:"#000", fontSize: 9}}>
{name}
</Text>
</Marker>
<Polygon
key={index}
coordinates={fixed_coordinates}
fillColor={this.hexToRgbA(color, 0.4)}
strokeColor={color}
strokeWidth={3}
>
</Polygon>
</View>
);
Proper complete solution for adding any component over polygon in center.
import {
View,
Text,
Button,
StyleSheet,
TouchableOpacity,
InteractionManager,
} from 'react-native';
import React, {useEffect, useRef, useState} from 'react';
import MapView, {Marker, Polygon} from 'react-native-maps';
import {useNavigation} from '#react-navigation/native';
import {COLOR_PLOT_BORDER} from '../../utils/colors';
let polygonsCoordinates = [
[
{latitude: 42.9348443, longitude: -72.287181},
{latitude: 42.9345929, longitude: -72.2832328},
{latitude: 42.9335415, longitude: -72.2834162},
{latitude: 42.9335572, longitude: -72.2852186},
{latitude: 42.9336671, longitude: -72.2869996},
{latitude: 42.934704, longitude: -72.2871498},
],
[
{latitude: 42.9345437, longitude: -72.2811199},
{latitude: 42.9347204, longitude: -72.2795911},
{latitude: 42.9343119, longitude: -72.2792585},
{latitude: 42.9341077, longitude: -72.2810394},
{latitude: 42.9345358, longitude: -72.2811146},
],
[
{latitude: 42.9329962, longitude: -72.2825093},
{latitude: 42.9333065, longitude: -72.2804494},
{latitude: 42.9322775, longitude: -72.2801382},
{latitude: 42.931979, longitude: -72.2824235},
{latitude: 42.9329726, longitude: -72.2824932},
],
];
export default function MapPlots() {
const mapRef = useRef(null);
const [region, setRegion] = useState({});
const [polygonCenters, setPolygonCenters] = useState([]);
useEffect(() => {
InteractionManager.runAfterInteractions(() => {
goToLocation();
getCenterOfAllPolygon();
});
}, []);
const getCenterOfAllPolygon = () => {
let centers = [];
polygonsCoordinates.map((v, i) => {
let c = getCenterPolygon(v);
centers.push(c);
});
setPolygonCenters(centers);
console.log('centers', centers);
};
const keeneRegion = {
latitude: 42.9329962,
longitude: -72.2825093,
latitudeDelta: 0.02,
longitudeDelta: 0.02,
};
const goToLocation = () => {
//complete this animation in 5 seconds
mapRef.current.animateToRegion(keeneRegion, 1 * 1000);
};
let getCenterPolygon = coordinates => {
let x = coordinates.map(c => c.latitude);
let y = coordinates.map(c => c.longitude);
let minX = Math.min.apply(null, x);
let maxX = Math.max.apply(null, x);
let minY = Math.min.apply(null, y);
let maxY = Math.max.apply(null, y);
console.log('adsasdad', minX, maxX, minY, maxY);
return {
latitude: (minX + maxX) / 2,
longitude: (minY + maxY) / 2,
};
};
const onPressPolygon = coordinates => {
let newCoordinates = getCenterPolygon(coordinates);
const goToRegion = {
...newCoordinates,
latitudeDelta: 0.01,
longitudeDelta: 0.01,
};
mapRef.current.animateToRegion(goToRegion, 1 * 1000);
};
return (
<View style={styles.container}>
<MapView
provider={MapView.PROVIDER_GOOGLE}
ref={mapRef}
style={styles.map}
initialRegion={{
latitude: 0, // This the position data
longitude: 0, // This is also position data
latitudeDelta: 200,
longitudeDelta: 1,
}}
loadingEnabled={true}
onRegionChangeComplete={r => setRegion(r)}>
{polygonsCoordinates.map((polygon, i) => (
<View key={i}>
<Polygon
coordinates={polygon}
strokeColor={COLOR_PLOT_BORDER} // fallback for when `strokeColors` is not supported by the map-provider
fillColor={i === 0 ? 'blue' : i === 2 ? 'green' : 'yellow'}
strokeWidth={0.3}
tappable
geodesic
onPress={() => onPressPolygon(polygon)}
/>
<Marker
anchor={{x: 0.5, y: 0.5}}
centerOffset={{x: 0.5, y: 0.5}}
zIndex={10}
coordinate={polygonCenters[i]}>
<Text note style={{color: '#000', fontSize: 15}}>
1001
</Text>
</Marker>
</View>
))}
</MapView>
<Button onPress={() => goToLocation()} title="Go to Current Location" />
<Text style={styles.text}>Current latitude{region.latitude}</Text>
<Text style={styles.text}>Current longitude{region.longitude}</Text>
</View>
);
}
const styles = StyleSheet.create({
container: {
...StyleSheet.absoluteFillObject,
flex: 1,
justifyContent: 'flex-end',
alignItems: 'center',
},
map: {
...StyleSheet.absoluteFillObject,
},
text: {
fontSize: 20,
backgroundColor: 'lightblue',
},
});

Undefined is not an object with MapView.Animated (refs are not working)

<MapView.Animated
ref={(mapView) => { map = mapView; }}
style={[styles.map, styleMap]}
initialRegion={{
latitude: LATITUDE,
longitude: LONGITUDE,
latitudeDelta: LATITUDE_DELTA,
longitudeDelta: LONGITUDE_DELTA,
}}>
</MapView.Animated>
<TouchableOpacity
onPress={()=>this.map.animateCamera({
center: {
latitude: this.state.userLocation.latitude,
longitude: this.state.userLocation.longitude,
},
pitch: 45>
</TouchableOpacity>
It rights me
Ofc there is exterior view and stuff... help please:)
Also I've tried to rename ref to map, making it 'var something:MapView,
it didnt work too
TRAIN ASKED ME TO DROP SOME CODE
TRAIN ASKED ME TO DROP SOME CODE
TRAIN ASKED ME TO DROP SOME CODE
TRAIN ASKED ME TO DROP SOME CODE
TRAIN ASKED ME TO DROP SOME CODE
TRAIN ASKED ME TO DROP SOME CODE
TRAIN ASKED ME TO DROP SOME CODE
TRAIN ASKED ME TO DROP SOME CODE
TRAIN ASKED ME TO DROP SOME CODE
class ChooseLocationScreen extends Component {
constructor(props) {
super(props);
this.map = React.createRef()
this.state = {
coordinate: new AnimatedRegion({
latitude: LATITUDE,
longitude: LONGITUDE,
latitudeDelta: 0,
longitudeDelta: 0,
}),
userLocation: new AnimatedRegion({
latitude: LATITUDE,
longitude: LONGITUDE,
latitudeDelta: 0,
longitudeDelta: 0,
}),
markerAnimation: new Animated.Value(0),
animation: new Animated.Value(0),
animationSides: new Animated.Value(1),
animationSides2: new Animated.Value(1),
mapActive: true,
isSearchScreen: false,
searchValue: '',
myGeo: false,
};
}
render() {
return (
<View style={{ flex: 1 }}>
<Animated.View style={[styles.mapContainer, animatedStyles]}>
<MapView.Animated
ref={(mapView) => { map = mapView; }}
showsUserLocation={true}
onRegionChange={() => this.onPanDrag()}
showsMyLocationButton={true}
onRegionChangeComplete={() => this.onRegionChangeComplete()}
style={[styles.map, styleMap]}
initialRegion={{
latitude: LATITUDE,
longitude: LONGITUDE,
latitudeDelta: LATITUDE_DELTA,
longitudeDelta: LONGITUDE_DELTA,
}}
zoomEnabled={this.state.mapActive}
scrollEnabled={this.state.mapActive}
onPress={this.mapPressBackHandler}>
</MapView.Animated>
</Animated.View>
<TouchableOpacity
onPress={() => this.map.animateCamera({
center: {
latitude: this.state.userLocation.latitude,
longitude: this.state.userLocation.longitude,
},
pitch: 4
})}
style={{ position: 'absolute', top: height * 3.5 / 4, right: width / 18, zIndex: 2, alignItems: 'center' }}>
{TextNewsIcon()}
</TouchableOpacity>
</View>
)
}
}
There is no such thing in this.
You can use this code
<MapView.Animated
ref={(mapView) => { this.map = mapView; }}
....
<TouchableOpacity
onPress={()=>this.map.animateCamera({
....
And animateCamera has no location parameters.
animateCamera
camera: Camera, { duration: Number }

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

Error while updating property 'coordinate' of a view managed by: AIRMapMarker (React native)

I have been searching the web for proper documentation in regards to this error, am in in no luck as i am unable to determine the cause of this error.
Here is the my entire code:
First section: setting the states
export default class Whereto extends Component<{}> {
constructor(props) {
super(props);
this.state = {
latitude: null,
longitude: null,
location: null,
error: null,
markers:[],
};
}
Second section Component did Mount
componentDidMount() {
navigator.geolocation.getCurrentPosition(
(position) => {
this.setState({
latitude: position.coords.latitude,
longitude: position.coords.longitude,
error: null,
});
//geocode api
var myApiKey = '';
fetch('https://maps.googleapis.com/maps/api/geocode/json?address=' + position.coords.latitude + ',' + position.coords.longitude + '&key=' + myApiKey)
.then((response) => response.json())
.then((responseJson) => {
//console.log('ADDRESS GEOCODE is BACK!! => ' + JSON.stringify(responseJson));
var locationName = responseJson.results[0].address_components.filter(x => x.types.filter(t => t === 'administrative_area_level_2').length > 0)[0].short_name;
//console.log(locationName);
this.setState({
location: locationName,
})
})
//nearby api
var apiPlaceskey = '';
//https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=-33.8670522,151.1957362&radius=500&type=restaurant&keyword=cruise&key=YOUR_API_KEY
fetch('https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=' + position.coords.latitude + ',' + position.coords.longitude + '&radius=2000&type=bus_station&key=' + apiPlaceskey)
.then((respplaces) => respplaces.json())
.then((responseJson2) => {
const markers = responseJson2.results.map((result) => ({
latlng: {
latitude: result.geometry.location.lat,
longitude: result.geometry.location.lng,
}
}));
this.setState({ markers });
});
},
(error) => this.setState({error: error.message}),
{enableHighAccuracy: true, timeout: 20000, maximumAge: 1000},
);
}
Third section: A function reserved when a a touchable button is tapped on my render and View section
fetchDirections = () => {
//directions api
var apiDirectionskey = '';
//const {location} = this.state;
const {latitude} = this.state;
const {longitude} = this.state;
fetch('https://maps.googleapis.com/maps/api/directions/json?origin=' + latitude + ',' + longitude + '&destination=' + goingto + '&mode=transit&transit_mode=bus&key=' + apiDirectionskey)
.then((resdirections) => resdirections.json())
.then((responseJson3) => {
console.log(responseJson3);
});
}
render(){
return(
<View style={styles.container}>
<Mainlogo/>
<TextInput style={styles.boxInput} underlineColorAndroid='rgba(0,0,0,0)' placeholder="Going To?"
underlineColorAndroid='transparent'
onChangeText={(dest) => this.setState({goingto : dest})}
/>
<TouchableOpacity style={styles.button} onPress={this.fetchDirections.bind(this)}>
<Text style={styles.textButton}> Go {this.props.type}</Text>
</TouchableOpacity>
<MapView style={styles.map}
region={{
latitude: this.state.latitude,
longitude: this.state.longitude,
latitudeDelta: 0.02,
longitudeDelta: 0.02
}}
>
</MapView>
<MapView.Marker
coordinate={{
latitude: this.state.latitude,
longitude: this.state.longitude,
latitudeDelta: 0.02,
longitudeDelta: 0.02
}}
image={require('../img/my-pin-512.png')}
title={'you are here'}
/>
{this.state.markers.map(marker => (
<MapView.Marker
coordinate={marker.latlng}
image={require('../img/busstop.png')}
/>
))}
</View>
)
}
}
To get to this stage a touchableopacity is tapped from my main profile page. I realised that i am using componendDidMount and a seperate fetch function to call another API call. It seems that it is not getting enough time to pupulate the states to cause the null values
I was receiving the lat, lng value as props so what worked for me was:
<Marker
coordinate={{
longitude: longitude ? longitude : 0,
latitude: latitude ? latitude : 0
}}
title={'owner location'}
/>
Set initial state values to 0 instead of null.
this.state = {
latitude:0,
longitude: 0,
latitudeDelta: 0.09,
longitudeDelta: 0.02,
};
Changing the initial value in coordinates from null to [] solved the issue.
<MapView.Polyline
strokeWidth={2}
strokeColor="#00ff00"
coordinates={coords}
/>
passing this helped me solve this:
coordinate={{
latitude: props && props.position && Number(props.position.latitude) ? Number(props.position.latitude) : 0,
longitude: props && props.position && Number(props.position.longitude) ? Number(props.position.longitude) : 0
}}
The fix is this: while you are updating the <Marker/> component, make sure that you are not passing null in the coordinates' latitude or longitude.
I faced the same error while looping through an object, where some of my fields were empty. I solved it by defaulting to 0 whenever there was an empty value.
Simple answer is the coordinate used in MapView, Markers, Circle etc... should be float/double value not string....
Usually {latitude: "27.123123",longitude: "85.2312321"}, is the problem should not be string should be {latitude: 27.123123,longitude: 85.2312321}
<Marker
coordinate={{
latitude: origin.details.geometry.location.lat,
longitude: origin.details.geometry.location.lng}}
title={'Origin'}
/>
<Marker
coordinate={{
latitude: destination.details.geometry.location.lat,
longitude: destination.details.geometry.location.lng}}
title={'Destination'}
/>
I might be late, but the trick above worked