I have a MapView that I want to add Markers to. I can successfully add Markers individually but I want to loop through an array of coordinates and add a marker for each location in the array. Whenever trying to run this code, I get an "Unexpected Token" error where the for loop begins. I have read suggestions about using the .map function on the array but that does not seem to work for me either. Any help would be highly appreciated.
const ViewNearbyScreen = ({
navigation, route
}) => {
const points = [
{
name: "Wendys",
lat: 37.4319983,
lng: -122.094,
},
{
name: "Taco Bell",
lat: 37.4419983,
lng: -122.104,
},
{
name: "Whataburger",
lat: 37.4519983,
lng: -122.114,
},
];
return (
<MapView
provider={PROVIDER_GOOGLE}
style={{flex: 1}}
region={{
latitude: 37.4219983,
longitude: -122.084,
latitudeDelta: 0.0922,
longitudeDelta: 0.0421
}}
ref={mapRef}
showsUserLocation>
{for(let i = 0; i < 3; i++) {
<Marker
coordinate={{
latitude: points[{i}].lat,
longitude: points[{i}].lng,
}}
title={points[{i}].name}
/>
}}
</MapView>
)
};
You can use the Array Map method to loop through the array elements.
points.map(item => { // each point in points array
return (
<Marker
coordinate={{
latitude: item.lat,
longitude: item.lng,
}}
title={item.name}
/>
)
})
The reason the map method wasn't working for you might be that you forgot to return your jsx.
Related
I am trying to get navigation directions using mapbox-sdk for react-native from npm package:
"#mapbox/mapbox-sdk": "^0.11.0"
And for rendering the directions returned by mapbox-sdk I am using the below npm package:
"#react-native-mapbox-gl/maps": "^8.1.0-rc.8",
Code I am using for retrieving directions:
import MapboxGL from '#react-native-mapbox-gl/maps'
// Mapbox SDK related package
import MapboxDirectionsFactory from '#mapbox/mapbox-sdk/services/directions'
import { lineString as makeLineString } from '#turf/helpers'
import GeoLocationService from '../../services/geolocation/GeoLocationService';
import GeoLocationCore from '#react-native-community/geolocation'
const accessToken = "ACESS_TOKEN_FROM_MAPBOX_API_DASHBOARD"
const directionsClient = MapboxDirectionsFactory({accessToken})
constructor(props) {
super(props);
this.state = {
longitude: 0,
latitude: 0,
orderLongitude: 0,
orderLatitude: 0,
route: null,
};
}
async componentDidMount() {
const {route} = this.props
// Lets say route.params contains the below object:
// { "longitude": "33.981982", "latitude": "-6.851599"}
console.log("Params from other screen: ", route.params)
MapboxGL.setAccessToken(accessToken)
MapboxGL.setConnected(true);
MapboxGL.setTelemetryEnabled(true);
const permission = await MapboxGL.requestAndroidLocationPermissions();
let latitude, longitude;
if(Platform.OS == "android") {
GeoLocationService.requestLocationPermission().then(() => {
GeoLocationCore.getCurrentPosition(
info => {
const { coords } = info
latitude = coords.latitude
longitude = coords.longitude
//this.setState({longitude: coords.longitude, latitude: coords.latitude})
this.setState({longitude: -6.873795, latitude: 33.990777, orderLongitude: route.params.longitude, orderLatitude: route.params.latitude})
console.log("your lon: ", longitude)
console.log("your lat", latitude)
this.getDirections([-6.873795, 33.990777], [route.params.longitude, route.params.latitude])
},
error => console.log(error),
{
enableHighAccuracy: false,
//timeout: 2000,
maximumAge: 3600000
}
)
})
}
}
getDirections = async (startLoc, destLoc) => {
const reqOptions = {
waypoints: [
{coordinates: startLoc},
{coordinates: destLoc},
],
profile: 'driving',
geometries: 'geojson',
};
const res = await directionsClient.getDirections(reqOptions).send()
//const route = makeLineString(res.body.routes[0].geometry.coordinates)
const route = makeLineString(res.body.routes[0].geometry.coordinates)
console.log("Route: ", JSON.stringify(route))
this.setState({route: route})
}
Code I am using for rendering road directions fetched by mapbox-sdk:
renderRoadDirections = () => {
const { route } = this.state
return route ? (
<MapboxGL.ShapeSource id="routeSource" shape={route.geometry}>
<MapboxGL.LineLayer id="routeFill" aboveLayerID="customerAnnotation" style={{lineColor: "#ff8109", lineWidth: 3.2, lineCap: MapboxGL.LineJoin.Round, lineOpacity: 1.84}} />
</MapboxGL.ShapeSource>
) : null;
};
Code I am using for rendering map and directions:
render() {
return (
<View style={{ flex: 1 }}>
<MapboxGL.MapView
ref={(c) => this._map = c}
style={{flex: 1, zIndex: -10}}
styleURL={MapboxGL.StyleURL.Street}
zoomLevel={10}
showUserLocation={true}
userTrackingMode={1}
centerCoordinate={[this.state.longitude, this.state.latitude]}
logoEnabled={true}
>
{this.renderRoadDirections()}
<MapboxGL.Camera
zoomLevel={10}
centerCoordinate={[this.state.longitude, this.state.latitude]}
animationMode="flyTo"
animationDuration={1200}
/>
</MapboxGL.MapView>
</View>
)
}
Now when I try to render the GeoJson retreived the road directions line not showing on map, so I thought maybe something wrong with my GeoJson and tested it from here but it looks fine:
https://geojsonlint.com/
GeoJson that I tested and looks okay:
{"type":"Feature","properties":{},"geometry":{"type":"LineString","coordinates":[[-6.880611,33.9916],[-6.882194,33.990166],[-6.882439,33.99015],[-6.882492,33.990028],[-6.882405,33.98991],[-6.878006,33.990299],[-6.87153,33.990978],[-6.871386,33.990925],[-6.871235,33.991016],[-6.869793,33.991165],[-6.870523,33.990292]]}}
Example of what I am trying to achieve:
What could be wrong in my code that makes road directions line not showing on map?
Found what was causing the <LineLayer/> not showing on map, removing the the attribute aboveLayerID from the following line:
<MapboxGL.LineLayer id="routeFill" aboveLayerID="customerAnnotation" style={{lineColor: "#ff8109", lineWidth: 3.2, lineCap: MapboxGL.LineJoin.Round, lineOpacity: 1.84}} />
So it becomes:
<MapboxGL.LineLayer id="routeFill" style={{lineColor: "#ff8109", lineWidth: 3.2, lineCap: MapboxGL.LineJoin.Round, lineOpacity: 1.84}} />
Result:
I've added MapView into my app but i want to initialize the region with the current user's live location, The code on the emulator changes the initial region to the location of google's HQ in CA (I know that's normal and i can change the emulator's location in settings) but on my own phone, the initial region doesn't change at all.
using the GEO location api preferred by react native:
const [region, setRegion] = useState({
latitude: -1.951670,
longitude: 30.157518,
latitudeDelta: 0.015,
longitudeDelta: 0.015,
})
useEffect(() => {
let currentLocation = true;
let newRegion = { latitude: null, longitude: null, latitudeDelta: null, longitudeDelta: null };
newRegion.longitudeDelta = region.longitudeDelta;
newRegion.latitudeDelta = region.latitudeDelta;
Geolocation.getCurrentPosition((info) => {
newRegion.latitude = info.coords.latitude
newRegion.longitude = info.coords.longitude;
},
(error) => {
console.log(error.code, error.message);
},
{ enableHighAccuracy: true, timeout: 15000, maximumAge: 10000 }
)
//To make sure no null is still present in the newReion obj
for (var key in newRegion) {
if (!newRegion[key]) {
currentLocation = false;
break;
}
}
if (currentLocation) {
setRegion(newRegion);
}
}, [])
//Map view implementation:
<MapView
provider={PROVIDER_GOOGLE}
ref={map => _map = map}
showsUserLocation={true}
style={styles.map}
initialRegion={initialPosition}
onRegionChangeComplete={(region) => setInitialPosition(region)}
/>
In our app, we are obtaining the user location when he logs in (click login -> get location -> save location in redux -> navigate to home screen). When the Home component mounts, it should use the location to get data from the area around the user.
In iOS, all markers render correctly but in Android devices, not all markers are rendered, only some of them (and oddly enough all of them are image1 or image2).
It is only when we call the getDataFromRegion function again that all markers render correctly. Any idea of what we are doing wrong?
class Login extends Component {
handleLogin = (u, p) => {
getLocation(location => {
let region = {
latitude: location.coords.latitude,
longitude: location.coords.longitude,
latitudeDelta: 0.06,
longitudeDelta: 0.06
}
/* save location in redux */
this.props.setLocation(region)
login(u, p).then(() => _gotoHome())
})
}
}
class Home extends Component {
componentWillMount() {
if(this.props.location !== undefined) {
initialRegion = {
latitude: this.props.location.latitude,
longitude: this.props.location.longitude,
latitudeDelta: 0.06,
longitudeDelta: 0.06
}
}
}
componentDidMount() {
/* set data in redux */
this.getDataFromRegion(initialRegion)
}
render() {
this.props.data.map((data, index) => data.visible ? <CustomMarker key={index} data={data}/> : null)
}
}
class CustomMarker extends Component {
render() {
const {data} = this.props
const coords = { latitude: data.lat, longitude: data.lng }
return (
<MapView.Marker
coordinate={coords}
onLoad={() => this.forceUpdate()}
tracksViewChanges={Platform.OS === 'android' ? false : true}
>
<Image
onLoad={() => this.forceUpdate()}
source={data.a === '0' ? image1 : image2}
style={{width: 60, height: 60}}
/>
</MapView.Marker>
)
}
}
It seems like removing the Image component and use the MapView.Marker prop image got it working. Also, rendering a dummy MapView.Marker with opacity: 0 inside the MapView solved the problem of appearing the default markers at the first render call.
I am using react-native-maps to show the map
I am getting my current location as follows:
navigator.geolocation.getCurrentPosition(
position => {
region = {
latitude: position.coords.latitude,
longitude: position.coords.longitude,
latitudeDelta: this.state.position.latitudeDelta,
longitudeDelta: this.state.position.longitudeDelta
}
this.setState(
{
position: {
latitude: region.latitude,
longitude: region.longitude,
latitudeDelta: region.latitudeDelta,
longitudeDelta: region.longitudeDelta,
error: null
}
})
})
But some times it showing the before location that I am in
Can any one suggest how to solve this by code
Thank you
You should consider using the parameter 'maximumAge'. e.g.
navigator.geolocation.getCurrentPosition(position => {
region: {
latitude: position.coords.latitude,
longitude: position.coords.longitude,
latitudeDelta: this.state.position.latitudeDelta,
longitudeDelta: this.state.position.longitudeDelta
}
this.setState(
{
position: {
latitude: region.latitude,
longitude: region.longitude,
latitudeDelta: region.latitudeDelta,
longitudeDelta: region.longitudeDelta,
error: null
}
})
}, err => {
console.log(err)
alert('fetching the position failed')
}, {enableHighAccuracy: false, timeout: 20000, maximumAge: 0})
As per MDN documentation :
The PositionOptions.maximumAge property is a positive long value indicating the maximum age in milliseconds of a possible cached position that is acceptable to return. If set to 0, it means that the device cannot use a cached position and must attempt to retrieve the real current position. If set to Infinity the device must return a cached position regardless of its age.
I have created an android app with CRNA, I can get the current location of the user by Expo's location API. But I can't figure out how to get the city name of a pinned location? This is my code so far:
class Map extends Component {
constructor(props) {
super(props);
this.state = {
region: {
latitude: 41.0141977,
longitude: 28.9638121,
latitudeDelta: 0.1,
longitudeDelta: 0.05,
},
x: {
latitude: 41.0238343,
longitude: 29.0335236,
},
regionName: "",
}
}
onDragEnd(e) {
this.setState({x: e.nativeEvent.coordinate});
}
onRegionChange(region) {
this.setState({region});
}
render() {
return (
<Modal
animationType={"slide"}
transparent={true}
visible={this.props.visible}
onRequestClose={this.props.changeState}
style={styles.modal}
>
<MapView
region={this.state.region}
onRegionChange={this.onRegionChange.bind(this)}
style={styles.map}
><MapView.Marker draggable
coordinate={this.state.x}
onDragEnd={this.onDragEnd.bind(this)}
/></MapView>
</Modal>
);
}
}
For that you need to use some for of geocoding.
In general look at the google maps page about geocoding.
And here is an npm package for react native.
As I googled more and more I learnt it's called reverse geocoding. So I created an redux action like this and it solved my problem very well:
export function fetchCityName(lat, lng) {
const link = `http://maps.googleapis.com/maps/api/geocode/json?latlng=${lat},${lng}`;
return dispatch => {
dispatch(startFetch());
return fetch(link)
.then(response => response.json())
.then(responseJson => {
const addressComponent = _.get(responseJson, 'results[0].address_components', []);
const getAreaName = zone => _.get(
addressComponent,
`[${_.findIndex(addressComponent, obj => _.includes(obj.types, zone))}].long_name`
);
const region = ' ' + getAreaName('administrative_area_level_1');
const country = ' ' + getAreaName('country');
const region2 = getAreaName('administrative_area_level_2');
const location = region2 ?
[region2, region, country].toString() :
region.concat(',' + country);
dispatch(getCityName(location));
})
.catch(console.error)