I'm using "react-native-maps": "0.29.4", and google provider on the Map component.
for some reason, using animateCamera on ios only and only in some cases (mainly after refreshing the app as in switching rtl to ltr for example either after initial getting user location GPS permission) has an offset that what supposed to be on the center going to the top left corner
https://youtu.be/3cLeZSIAaVk
the video shows the bag while using handlePressMyLocation function
const handleAnmiateToRegion = useCallback((center: IMapLocation, zoom: number = undefined) => {
mapRef.current
? mapRef.current.animateCamera({ center, zoom })
: setTimeout(() => {
handleAnmiateToRegion(center, zoom)
}, 100)
}, [])
const handlePressMyLocation = useCallback(() => {
handleAnmiateToRegion(location)
}, [location.latitude, location.longitude])
again, this is never happening on android, and also on ios sometimes it's working normally, but in case a session has this bug, it gonna happen all the time and in all of animateCamera usage (there're more cases for this handleAnmiateToRegion as init focusing + zooming or in case of pressing some of the markers)
any thoughts? also tried to change animateCamera to animateToRegion, as well as calling the functions with 12 digits after . instead of 5 (as given by Geolocation.watchPosition) but the same bug occurs)
thanks in advance!
(in case more code will help, pls write in a comment and I'll add)
For some reason, rendering the map only after I got the user location (using memo for making sure it indeed happen and for avoiding unnessecary rerendering) and setting initialRegion prop on Map fixed the issue
<MapView
provider={PROVIDER_GOOGLE}
key={this.state.forceRefresh}
style={styles.gmapView}
showsUserLocation
ref={(ref) => (this.mapView = ref)}
followUserLocation
showsMyLocationButton
snappedminZoomLevel={Platform.OS == "ios" ? this.state.zoom : 12}
/* minZoomLevel={11}
maxZoomLevel={17} */
showsMyLocationButton={false}
initialRegion={{
latitude: latlong.lat || currentLocation.latitude,
longitude: latlong.lng || currentLocation.longitude,
latitudeDelta: this.state.latitudeDelta,
longitudeDelta: this.state.longitudeDelta,
}}
onRegionChange={(data) =>
this.setState(
{
newLatitude: data.latitude,
newLongitude: data.longitude,
zoom:Math.round(Math.log(360 / data.longitudeDelta) / Math.LN10),
latitudeDelta: data.latitudeDelta,
longitudeDelta: data.longitudeDelta,
},
() => {
console.log("data ==> "+JSON.stringify(data))
}
)
}
onPress={(e) =>{
this.animate(e)
}
}
>
</MapView>
animate(e){
let lat = e?.nativeEvent?.coordinate?.latitude + 0.004000;
let long = e?.nativeEvent?.coordinate?.longitude - 0.004000;
let r = {
latitude: lat,
longitude: long,
latitudeDelta: 0.38,//this.state.latitudeDelta,
longitudeDelta: 0.28,//this.state.longitudeDelta,
};
this.mapView.animateToRegion(r, 300);}
can you try this? may be it's helping you
Related
I am using capacitor geolocation plugin to find current location coordinates(latitude and longitude).
const coordinates = await Geolocation.getCurrentPosition({enableHighAccuracy:true});
const center = {lat: coordinates.coords.latitude, lng: coordinates.coords.longitude};
But in Iphone its taking around 45sec to 1.5 mins to fetch current location.
I have also used below code. But this is sometime fast sometime slow.
const id = await Geolocation.watchPosition({}, (coordinates, err) => {
Geolocation.clearWatch({id});
if(err) {
console.log(err)
}
console.log('getCenter ios',coordinates);
const center = {lat: coordinates.coords.latitude,
lng:coordinates.coords.longitude};
});
Is there any other implementation or free/paid plugin available, which can fetch current location coordinates faster on iphone.
My app is loading a HERE map, and works fine with a set of manually entered coordinates as the centre point.
I have implemented Geolocator in another part of the app to produce the users location which is then implemented into a function to find places near their current location & display on map.
I have now taken the Geolocator position finder and want to use it to open the map on the users location. The code uses async and await to get users coordinates.
The map open function does not want to accept async/ await, yet I have tried building it within its own class and pulling the coords, without success.
I am relatively new and any advice is greatly appreciated
Async & Await are currently red underlined in the 'function to open map', and when I change MapMarkerExample to mapMarkerExample at the top of 'function to open map', _mapMarkerExample = MapMarkerExample (_showDialog, hereMapController); is red underlined on `command to open map'
Command to open map
void _onMapCreated(HereMapController hereMapController) {
hereMapController.mapScene.loadSceneForMapScheme(MapScheme.normalDay, (MapError error) {
if (error == null) {
_mapMarkerExample = MapMarkerExample (_showDialog, hereMapController);
} else {
print("Map scene not loaded. MapError: " + error.toString());
}
});
}
Function to open map
MapMarkerExample(ShowDialogFunction showDialogCallback, HereMapController hereMapController) async {
_showDialog = showDialogCallback;
_hereMapController = hereMapController;
Position position = await Geolocator.getCurrentPosition(desiredAccuracy: LocationAccuracy.high);
var lat = position.latitude;
var long = position.longitude;
double distanceToEarthInMeters = 8000;
_hereMapController.camera.lookAtPointWithDistance(
GeoCoordinates(lat, long), distanceToEarthInMeters);
_setTapGestureHandler();
_showDialog("Note", "Tap markers for more.");
}
The problem is that MapMarkerExample() is a constructor and constructors cannot be executed asynchronously.
One possible way to solve this is to not set the coords in the MapMarkerExample() constructor. Just call it to create the instance. And then in a second method _setMapTarget() you can set the center coords of the map.
_setMapTarget() is marked async, so it will be executed immediately and it will not block _onMapCreated(). But it will do the magic a little bit later, fetch the position and once it has the position, it will update the camera.
If fetching the position takes to long, then you would see for that time a default camera position of the map.
void _onMapCreated(HereMapController hereMapController) {
hereMapController.mapScene.loadSceneForMapScheme(MapScheme.normalDay, (MapError? error) {
if (error == null) {
_mapMarkerExample = MapMarkerExample(_showDialog, hereMapController);
_setMapTarget(hereMapController);
} else {
print("Map scene not loaded. MapError: " + error.toString());
}
});
}
Future<void> _setMapTarget(HereMapController hereMapController) async {
Position position = await Geolocator.getCurrentPosition(desiredAccuracy: LocationAccuracy.high);
var lat = position.latitude;
var long = position.longitude;
double distanceToEarthInMeters = 8000;
hereMapController.camera.lookAtPointWithDistance(GeoCoordinates(lat, long), distanceToEarthInMeters);
}
I have a React Native project using react-native-maps:
getRegionForCoordinates(points) {
// points should be an array of { latitude: X, longitude: Y }
let minX, maxX, minY, maxY;
var arr = [];
Object.keys(points).map(key => {
var point = points[key];
arr.push([{latitude: point.latitude, longitude: point.longitude}])
})
points = arr;
var first = points[0];
minX = first[0].latitude;
maxX = first[0].latitude;
minY = first[0].longitude;
maxY = first[0].longitude;
// calculate rect
points.map((point) => {
minX = Math.min(minX, point[0].latitude);
maxX = Math.max(maxX, point[0].latitude);
minY = Math.min(minY, point[0].longitude);
maxY = Math.max(maxY, point[0].longitude);
});
const midX = (minX + maxX) / 2;
const midY = (minY + maxY) / 2;
const deltaX = (maxX - minX);
const deltaY = (maxY - minY);
return {
latitude : midX,
longitude : midY,
latitudeDelta : deltaX,
longitudeDelta : deltaY
};
}
componentDidMount() {
var event = this.props.event;
var mapData = JSON.parse(event.map);
var map = mapData[0];
var markers = [];
Object.keys(map.markers).map(key => {
var marker = map.markers[key];
var obj = [{ latitude: parseFloat(marker.lat), longitude: parseFloat(marker.lng) }];
markers.push(obj[0]);
});
var region = this.getRegionForCoordinates(markers);
setTimeout(() => {
this.ref.animateToRegion(region, 1);
}, 5000)
}
renderMap() {
var event = this.props.event;
var mapData = JSON.parse(event.map);
var map = mapData[0];
return (
<View>
<MapView
provider={PROVIDER_GOOGLE}
style={mapStyles.map}
ref={(map) => {
this.ref = map
}}
customMapStyle={customMapStyle}
key={ `${Date.now()}` }
>
{
map.markers.map(marker => {
return (
<EventMapMarker marker={marker} navigation={this.props.navigation} />
)
})
}
</MapView>
</View>
)
}
In this code I am trying to animate to a region based on the markers that will be displayed on the map. The latitude, longitude, latitudeDelta and longitudeDelta are correct as they work for Android.
However, on iOS it animates to a completely wrong region, both in the simulator and on the device.
Setting initialRegion or region doesn't seem to make any difference.
I have tried a bunch of different things, like animating in the onMapReady function, using a setTimeout to delay the animate, updating/downgrading react-native-maps, etc.. I don't know if this is a bug or something I have set incorrectly in my project.
React Native version is 0.59.0.
react-native-maps version is 0.27.1.
It doesn't work if you set provider={PROVIDER_GOOGLE}. Removing that, it works even on IOS. Not sure why. I am facing the same issue.
Use the timing method:
https://jakallergis.com/google-maps-in-react-native-part-3-advanced-usage
This works for me
There are several possible causes that I have found so far, depending on the exact nature of how your map is animating to the wrong region.
Centre of target is at the top left of the map.
I am not entirely certain why this one occurs. I just know that manually setting the map's position after a short timeout after it's creation seems to stop it from occurring.
const [mapStyle, setMapStyle] = useState({ height: 0 });
useEffect(() => {
setTimeout(() => {
setMapStyle({});
}, 2000);
}, []);
return <>
<MapView provider={PROVIDER_GOOGLE}
style={[StyleSheet.absoluteFillObject, mapStyle]} ...
My best guess is somewhere along the lines of this:
I tell it to align the map to a marker.
Because of some reason, a race condition of some form, perhaps, it thinks at this stage the map's height is 0x0.
Because of this, it sets the map's position to that marker but with no width or height.
Then something happens and it has to scale the map up to meet the actual width and height of the map view, but it anchors to the top left corner, so that's where the centre of the region is shown.
Manually resetting the height/width seems to kick it and stop it from thinking the map's height is 0x0, so it doesn't have the same problem.
For whatever reason, this issue for me was intermittent and also specific to iOS google maps.
Map stays at current position but zoom level is correct
This probably means your latitude delta's too large.
Specifying a region that includes any latitude value not between 90.0 or -90.0 seems to prevent the map from animating to that region. Instead it will only set the zoom level, leaving the camera at the current position.
In other words, if abs(latitude) + latitudeDelta / 2 is greater than 90, then you will see this issue.
Animating to 180.0 longitude always
Specifying a longitude delta greater than 180 will cause the map to animate to 180.0 longitude always.
In a recent project I had to implement a geolocation tracking feature for a web app that shows users' data on a map powered by LeafletJS/Mapbox. The Leaflet doc for "map.locate()" API and the "watch" locate option is helpful but I couldn't find a good example of how they worked together, or what the continuous location tracking looks like using Leaflet.
Since I couldn't find a good example of this anywhere, I decided to create my own. Try the working web app on your mobile device. Hope this helps others.
var marker, circle;
function onLocationFound(e) {
var radius = e.accuracy / 2;
if(marker) {
map.removeLayer(marker);
}
if(circle) {
map.removeLayer(circle);
}
marker = L.marker(e.latlng);
circle = L.circle(e.latlng, radius);
marker.addTo(map)
.bindPopup("You are within " + radius + " meters from this point").openPopup();
circle.addTo(map);
}
function onLocationError(e) {
alert(e.message);
}
map.on('locationfound', onLocationFound);
map.on('locationerror', onLocationError);
map.locate({setView: true,
maxZoom: 20,
watch: true,
enableHighAccuracy: true,
maximumAge: 15000,
timeout: 3000000});
The working app http://jsfiddle.net/hanislovingit/7n2wf0kg/12
I'm using gmaps4rails to display a single marker, but I can't get it to not show a flash of lat/lon 0,0 water before panning over to the marker.
My (coffeescript) code is very simple:
handler = Gmaps.build('Google')
handler.buildMap { provider: {}, internal: { id: 'my-map-id' } }, ->
marker = handler.addMarker
lat: 41.0
lng: -96.0
marker.panTo()
handler.getMap().setZoom(14)
The map displays blue water then quickly jumps over to the desired location. I've tried using the bounds-oriented methods instead of the marker.panTo(), with the same results:
handler.bounds.extendWith(marker)
handler.fitMapToBounds()
handler.getMap().setZoom(14)
It seems like I need to either prevent display of the map until the marker and location is set, or I need to add the markers in earlier. Neither of which I've figured out how to do.
Thanks to the quick tip from #apneadiving, this took care of it:
lat = 41.0
lng = -96.0
options =
center: new google.maps.LatLng(lat, lng)
zoom: 14
handler = Gmaps.build('Google')
handler.buildMap { provider: options, internal: { id: 'contact-map' } }, ->
marker = handler.addMarker
lat: lat
lng: lng