Update map markers dynamically on slider change - React Native - react-native

I have a little problem with rendering markers.
Everything gets slow and laggy.
You can see it on this video: https://streamable.com/fjqe7
Is there a way to render my Markers smoother?
this is what I tried
<View style={styles.slider}>
<Slider
maximumValue={1000}
minimumValue={100}
step={50}
value={this.state.newRadius}
onValueChange={newRadius => {
this.setState({newRadius})
this.getLocation()
}}
/>
<View>
<Text>Radius: {this.state.newRadius} meter</Text>
</View>
</View>
onValueChange I'm loading the getLocation()
my getLocation is for showing and filtering my Markers inside my RadiusValue
getLocation(){
let { region } = this.state;
let { latitude, longitude } = region;
let markers = spielanlagen.map(marker => {
let name = marker.name
let image = marker.image
let street = marker.street
console.log(name);
console.log(marker.coordinate);
let coords = marker.coordinate
return {
coordinate: {
latitude: coords[0],
longitude: coords[1],
},
name: marker.name,
street: marker.street,
image: marker.image
}
}).filter(marker => {
let distance = this.calculateDistance(latitude, longitude, marker.coordinate.latitude, marker.coordinate.longitude);
return distance <= this.state.newRadius;
});
this.setState({
markers: markers,
loaded: true,
});
};
calculateDistance(origLat, origLon, markerLat, markerLon) {
return geolib.getDistance(
{latitude: origLat, longitude: origLon},
{latitude: markerLat, longitude: markerLon}
);
}
I hope there is a better solution with re-rendering the markers.

Related

(React Native) Polyline Maps + AsyncStorage | Attempted to assign to readonly property

so I'm trying to: when a button is called, it does a setInterval that every minute saves the latitude and longitude, so I can build a polyline that conennects them.
When the button title is "Iniciar" (start) it does what I said and then the title changes to "Concluir", when the title is "Concluir" (finish) it saves the coords with AsyncStorage.
Here is some of the code with a few comments (I removed the part when it gets and updates the coords becouse it's working just fine)
export default class geolocation extends Component {
constructor(props) {
super(props);
this.state = {
initialPosition: {
latitude: 0,
longitude: 0,
latitudeDelta: 0,
longitudeDelta: 0,
kind: '',
},
markerPosition: { //marker where I am right now
latitude: 0,
longitude: 0,
kind: '',
},
refreshIntervalId: null, //so I can cancel the setInterval
markers: [], //here it's all the markers that I'll get from the setInterval
titleButtonStartFinish: 'Iniciar', //so I can change the title to see if i'm starting or finishing
};
AsyncStorage.getItem('markers').then((value) => { //so I can get the markers I saved in Async
if (value) {
const s = JSON.parse(value);
this.setState({ markers: s });
}
});
this.ButtonStartFinishOnPress = this.ButtonStartFinishOnPress.bind(this);
}
async ButtonStartFinishOnPress() {
let s = this.state;
if (s.titleButtonStartFinish === 'Iniciar') {
s.titleButtonStartFinish = 'Concluir';
s.markers = [];
s.refreshIntervalId = setInterval(() => {
s.markers.push(this.state.markerPosition);
}, 60000);
this.setState(s);
}
else if (s.titleButtonStartFinish === 'Concluir') {
s.titleButtonStartFinish = 'Iniciar';
clearInterval(s.refreshIntervalId);
console.log(JSON.stringify(s.markers));
if (s.markers) {
const x = JSON.stringify(s.markers);
await AsyncStorage.setItem('markers', x);
}
this.setState(s);
}
}
render() {
return (
<View style={styles.container}>
<MapView
provider={PROVIDER_GOOGLE}
style={styles.map}
region={this.state.initialPosition}
>
<Polyline // the polyline connecting all the markers
coordinates={this.state.markers}
strokeColor="#B24112"
strokeWidth={4}
/>
<Marker coordinate={this.state.markerPosition}> //showing the marker where i am right now
<View style={styles.radius}>
<View style={styles.marker} />
</View>
</Marker>
{this.state.markers.map((marker) => ( //showing where all the markers are
<Marker coordinate={marker} />
))}
</MapView>
<ButtonStartFinish
title={this.state.titleButtonStartFinish}
onPress={() => this.ButtonStartFinishOnPress()}
/>
</View>
);
}
}
Everything seems to be working just fine, until I add the Polyline thing.
It get the coords, it builds the polyline, then I can close the app and open again and the coords and the polyline comes back (becouse I saved them in the AsyncStorage), BUT when I do that and then i hit the start button again, it was supposed to delete the coords in "this.state.markers" and start saving new coords in the setInterval.. but it doesn't, that's when this error happens. click here to see the error
Got it!
This bug can happen when you are trying to make an array.push in a string instead of an array object, when you make your pushing in the same array into the the object more then once, or when you are not using the setState correctly.
In my case, I just needed to save the markers array in another const;
then JSON.parse(the backup const);
then the markers array = [];
then i use the .forEach function in the backup const, like
backup.forEach((marker) => { this.state.markers.push(markers)});
That's the way I found so my code won't try to push an array to a string
I tried to JSON.parse(markers array) and JSON.parse(the marker I want to push) but that wasn't enought

How can I display description of a marker on the map with Reactnative

Hey guys I'm stucking on my code.
I'm able to display mulitple markers from a geojson file.
but I dont know how to clickable the markers to get the description which is set in the geojson file.
this is how I'm getting the coordinations but I don't have a clue how to fetch some important informations of this location.
getLocations() {
return fetch('http://media-panda.de/bp/whs.geojson')
.then(response => response.json())
.then(responseData => {
let { region } = this.state;
let { latitude, longitude } = region;
let markers = responseData.features.map(feature => {
let coords = feature.geometry.coordinates
return {
coordinate: {
latitude: coords[1],
longitude: coords[0],
}
}
}).filter(marker => {
let distance = this.calculateDistance(latitude, longitude, marker.coordinate.latitude, marker.coordinate.longitude);
return distance <= this.state.value;
});
this.setState({
markers: markers,
loaded: true,
});
}).done();
}
and my view is like:
<MapView.Animated
style={styles.map}
region={this.state.region}
showsUserLocation={true}
>
{this.state.markers.map(marker => (
<MapView.Marker
key={Math.random()}
coordinate={marker.coordinate}
description={marker.description}
/>
))}
<MapView.Circle
center= {this.state.region}
radius = { this.state.value }
strokeWidth = { 1 }
strokeColor = { '#1a66ff' }
fillColor = { 'rgba(230,238,255,0.5)' }
/>
</MapView.Animated>
Ok, I see your problem now, you are trying to set description outside of the getLocation function but you are still trying to use responseData which only exists inside of the getLocations function.
You are already mapping over each item in the responseData array, just add the title and description here.
You can easily do it inside the function you already have;
let markers = responseData.features.map(feature => {
let coords = feature.geometry.coordinates
let name = feature.properties.Name
let description = feature.properties.description
return {
coordinate: {
latitude: coords[1],
longitude: coords[0],
},
title: name,
description: description
}
})

React Native Null Reference - Maps & Markers (Android)

Hey Guys Iam getting an error on my Android Devices.
On Iphone it works very well I'am getting my Markers in maps but on Android iam getting this Error
Click for the Image
Since i upgraded the Code with geolib where iam filtering markers out which are not near to me it won't work on Android...
Anybody an idea?
this is my Code:
import React from 'react';
import MapView from 'react-native-maps';
import Marker from 'react-native-maps';
import Geolib from 'geolib';
import {
View,
Text,
StyleSheet,
Button,
} from "react-native";
const geolib = require('geolib');
class Grillplaetze extends React.Component {
constructor() {
super();
this.state = {
markers: [],
loaded: false
}
}
componentDidMount() {
this.getPosition();
}
getPosition(){
navigator.geolocation.getCurrentPosition(
(position) => {
console.log(position);
this.setState({
region: {
latitude: position.coords.latitude,
longitude: position.coords.longitude,
latitudeDelta: 0.020,
longitudeDelta: 0.020,
}
}, () => this.getLocations());
},
(error) => this.setState({ error: error.message }),
{ enableHighAccuracy: false, timeout: 200000, maximumAge: 1000 },
);
}
getLocations() {
return fetch('http://media-panda.de/bp/whs.geojson')
.then(response => response.json())
.then(responseData => {
let { region } = this.state;
let { latitude, longitude } = region;
let markers = responseData.features.map(feature => {
let coords = feature.geometry.coordinates
return {
coordinate: {
latitude: coords[1],
longitude: coords[0],
}
}
}).filter(marker => {
let distance = this.calculateDistance(latitude, longitude, marker.coordinate.latitude, marker.coordinate.longitude);
return distance <= 500;
});
this.setState({
markers: markers,
loaded: true,
});
}).done();
}
calculateDistance(origLat, origLon, markerLat, markerLon) {
return geolib.getDistance(
{latitude: origLat, longitude: origLon},
{latitude: markerLat, longitude: markerLon}
);
}
render() {
return (
<View style={styles.container}>
<MapView.Animated
style={styles.map}
region={this.state.region}
showsUserLocation={true}
>
{this.state.markers.map(marker => (
<MapView.Marker
coordinate={marker.coordinate}
/>
))}
<MapView.Circle
key = { (this.state.latitude + this.state.longitude).toString() }
center = { this.state.region }
radius = { 500 }
strokeWidth = { 1 }
strokeColor = { '#1a66ff' }
fillColor = { 'rgba(230,238,255,0.5)' }
/>
</MapView.Animated>
</View>
);
}
}
export default Grillplaetze;
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#ecf0f1',
},
map: {
width: "100%",
height: "100%",
},
})
Your errors aren't related to your implementation of the geolib but instead they are due to your implementation of the MapView.Circle.
If we look at the documentation the MapView.Circle we see the following:
| Prop | Type | Default | Note |
|----------|----------|------------|------------------------------------------------|
| `center` | `LatLng` | (Required) | The coordinate of the center of the circle .
| `radius` | `Number` | (Required) | The radius of the circle to be drawn (in meters)
Both the center and the radius are required fields.
If we look at your code:
<MapView.Circle
key = { (this.state.latitude + this.state.longitude).toString() }
center = { this.state.region }
radius = { 500 }
strokeWidth = { 1 }
strokeColor = { '#1a66ff' }
fillColor = { 'rgba(230,238,255,0.5)' }
/>
It would appear that you have set them, however you have not actually set the region. You can confirm this by checking your initial state.
constructor () {
super();
this.state = {
markers: [],
loaded: false
}
}
Notice that you have not set an initial region for the map. This is what is causing your error. The app is trying to handle the undefined value for the region.
To overcome this the easiest way is to set an initial region for the map in state.
Something like this:
constructor () {
super();
this.state = {
markers: [],
loaded: false,
region: {
latitude: 0,
longitude: 0,
latitudeDelta: 0.020,
longitudeDelta: 0.020
},
latitude: 1,
longitude: 1
};
}
If you app is for a specific region then it may make sense to pick an initial region that is close to where you app is going to be used.
Also note in your MapView.Circle code you are also using undefined values of latitude and longitude for the key. I don't think that you need to define a key property for the MapView.Circle. I cannot find any mention of this being a requirement in the documentation.
Making the above changes allows the code to work.
Some other points.
You are importing geolib twice. You only need to do it once. You should either have import GeoLib from 'geolib'; or const geolib = require('geolib'); you don't need both. Seeing as you are using geolib with a lower case, I would just remove import GeoLib from 'geolib';
You are importing Markers from react-native-maps in the wrong way. It should be imported as import { Markers } from 'react-native-maps, however you are using the Markers as MapView.Markers which is absolutely fin. I think you can remove the unused and incorrect import Markers from 'react-native-maps
MapView.Animated I am not 100% that this is correct or required. I haven't seen it used in this way before. However if it is not causing you issues then I suppose it isn't really a problem.
You should also add a key prop on your Markers so that you suppress the warning that it is missing. This should be something unique.

Getting error when changing the coordinates of region on react-native-maps

I am getting an error "You attempted to set the key latitude with the value xx.xxxxx on an object that is meant to be immutable and has been frozen when my app starts or when i try to change the coordinates of the region via callback funciton.
My goal is to be able to change the region location from input field like on Google Maps. But whenever i change the coordinates i get this error. I tried with rerendering the map with the new coordinates and that works, but that will do lots of requests.
Is there a way of giving the region new coordinates and showing it without rerendering the whole map ?
Here is my code:
export default class Map extends Component{
constructor(){
super();
this.state = {
region: {
latitude: 37.78825,
longitude: -122.4324,
latitudeDelta: 0.0922,
longitudeDelta: 0.0421
},
radius: 500
}
}
componentWillMount(){
}
regionChange = (region) =>{
let reg = this.state.region;
reg.latitude = region.latitude;
reg.longitude = region.longitude;
this.setState({region:reg});
}
changeRadius = (radius) => {
this.setState({radius});
console.log("RADIUS", this.state.radius);
}
render(){
return (
<View style={ styles.map }>
<MapView
provider={PROVIDER_GOOGLE}
style={ styles.map }
region={this.state.region}
onRegionChangeComplete={(region) => {this.regionChange(region)}}
onPress={(event) => this.regionChange(event.nativeEvent.coordinate)}
>
<MapView.Circle
center = { this.state.region }
radius = { this.state.radius }
strokeWidth = { 1 }
strokeColor = { '#1a66ff' }
fillColor = { 'rgba(230, 238, 255, 0.5)' }
onRegionChangeComplete = {(region) => {this.regionChange({region});console.log(region)}}
/>
<Marker
coordinate = { this.state.region }
title = {"Marker"}
description = {"Marker description"}
/>
</MapView>
<Slider
step={50}
maximumValue={2000}
onValueChange={(value) => this.changeRadius(value)}
value={this.state.radius}
style={{marginTop:10}}
/>
<Autocomplete regionChange={(reg) => this.regionChange(reg)} />
</View>
)
}
}
Objects are not primitive data types. So, they are passed by value by reference. In your code when you did let reg = this.state.region you have made a reference to this.state.region. So, when you mutate reg, you mutate state directly which is a big no in react.
I suggest you to use spread operator to make a new copy of state.
let reg = { ...state, {} }

How to animate marker and polyline with react-native-maps

I'm using react native maps, redux, redux thunk (and a lot of other cool stuffs)
Any ideas about how to animate my marker and my polyline like this
map animation on dribbble
I already have the markers and the polyline on my map and I know how to move the map. I want to add 3 effects :
the pulse effect on the marker,
draw the polyline from start to arrival with a fancy animation
make a gradient color on the polyline
Thanks everyone !
It does not appear that you can animate the drawing of a polyline in react native maps, but you can give it a gradient color with the following code (iOS only):
import MapView, { Polyline } from 'react-native-maps';
<MapView>
<Polyline
coordinates={[
{ latitude: 37.8025259, longitude: -122.4351431 },
{ latitude: 37.7896386, longitude: -122.421646 },
{ latitude: 37.7665248, longitude: -122.4161628 },
{ latitude: 37.7734153, longitude: -122.4577787 },
{ latitude: 37.7948605, longitude: -122.4596065 },
{ latitude: 37.8025259, longitude: -122.4351431 }
]}
strokeColor="#000" // fallback for when `strokeColors` is not supported by the map-provider
strokeColors={[
'#7F0000',
'#00000000', // no color, creates a "long" gradient between the previous and next coordinate
'#B24112',
'#E5845C',
'#238C23',
'#7F0000'
]}
strokeWidth={6}
/>
Here is an example of an animated Marker as well:
import Mapview, { AnimatedRegion, Marker } from 'react-native-maps';
getInitialState() {
return {
coordinate: new AnimatedRegion({
latitude: LATITUDE,
longitude: LONGITUDE,
}),
};
}
componentWillReceiveProps(nextProps) {
const duration = 500
if (this.props.coordinate !== nextProps.coordinate) {
if (Platform.OS === 'android') {
if (this.marker) {
this.marker._component.animateMarkerToCoordinate(
nextProps.coordinate,
duration
);
}
} else {
this.state.coordinate.timing({
...nextProps.coordinate,
duration
}).start();
}
}
}
render() {
return (
<MapView initialRegion={...}>
<MapView.Marker.Animated
ref={marker => { this.marker = marker }}
coordinate={this.state.coordinate}
/>
</MapView>
);
}
More examples can be seen here: https://github.com/react-community/react-native-maps