React-native-maps MapView.Circle - react-native

I'm trying to get same size of my circle while zooming. I was tryging to do that with settings "scale" but it also doesnt work. How can i do that?
Could someone show me how can do that, maybe with any example ?
<MapView.Circle
key = { (this.state.longitude + this.state.latitude).toString() }
center = {{latitude: this.state.latitude,
longitude: this.state.longitude} }
radius = { 100 }
strokeWidth = { 1 }
strokeColor = { '#1a66ff' }
fillColor = { '#1a66ff' }
/>
Best regards

One way to do it is to save the current map region to the state, this expresses the coordinate domain which the viewer sees...
onRegionChange(region) {
// Update state
this.setState({ mapRegion: region });
}
<MapView
onRegionChange={this.onRegionChange.bind(this)}
/>
With this, you can use simple trigonometry to resize the radius kind of like this...
size = {radius / Math.sqrt(this.state.mapRegion.longitudeDelta*this.state.mapRegion.longitudeDelta + this.state.mapRegion.latitudeDelta*this.state.mapRegion.latitudeDelta)}

Related

if-else statement inside jsx not working as expected

I am trying to animate an image in and out when clicked using React Native reanimated, but the JSX if else condition is not working quite right. Below is the code that works, but only works when clicked for the first time. The state toggled is set to true, so when clicked again it should set the size back to the original and the image should animate back to it and vice versa.
The setup is like so:
export default () => {
const newNumber = useSharedValue(100);
const [Toggled, setToggled] = useState(false);
const style = useAnimatedStyle(() => {
return {
width: withSpring(newNumber.value),
height: withSpring(newNumber.value, { damping: 10,
stiffness: 90, }),
};
});
onPress={() => {
{Toggled ? newNumber.value = 100 : newNumber.value = 350; setToggled(true)}
}}
The problem is when I try to add the newNumber.Value = 100 when setting Toggled to false, it gives me an error. I try to add it like this :
{Toggled ? newNumber.value = 100; setToggled(false) : newNumber.value = 350; setToggled(true)}
Why does it accept the first one but not the second?
If I use this, it works, but can it be done the other way?
const isToggled = Toggled;
if (isToggled) {
// alert('Is NOT Toggled');
newNumber.value = 100;
setToggled(false)
} else {
// alert('Is Toggled');
newNumber.value = 350;
setToggled(true)
}
Thanks
It looks you are just setting a value to newNumber base on Toggled, and then setting the Toggled to its opposite value. So why not do
onPress={() => {
newNumber.value = Toggled ? 100 : 350
setToggled(prev=>!prev)
}}

Render Polygon only if within MapView in React Native

I have a long list of areas loaded from a SQLite database into react-native-maps. Each area has a particular status, and a fillColor that gets calculated based on its status. As some areas end up having hundreds of Polygons, the maps gets slower the more areas are calculated. Is there a way to detect if a Polygon is within the MapView to hide it when is not within the observable map?
So far I have a memoized component that gets the coordinates and a couple of helper function to get the color based on the area. The looped component gets then injected inside the MapView.
const Areas = useMemo(
() =>
areas &&
areas.map((area: Area) => {
console.log('rendering');
const coordinates = getCoordinates(area.geometry);
const areaColor = getAreaColor(area.status);
return (
<View key={area.CODE}>
<Polyline
strokeWidth={2}
fillColor={'transparent'}
coordinates={coordinates}
strokeColor={areaColor}
tappable={true}
onPress={() => handlePressArea(area)}
/>
</View>
);
}),
[areas]
);
const getCoordinates = (coords: string): LatLng[] => {
const geometry = JSON.parse(coords);
const output = geometry[0].map((item: Point[]) => ({
latitude: item[1],
longitude: item[0],
}));
return output;
};
const getAreaColor = (status: Area['status']): string => {
if (status === STATUS.ONE) {
return 'rgba(54, 155, 247, 0.6)';
} else if (status === STATUS.TWO) {
return 'rgba(240, 54, 0, 0.6)';
} else {
return 'rgba(235, 149, 50, 0.6)';
}
};
Eventually I mount the component like this:
<MapView
initialRegion={region}
provider={PROVIDER_DEFAULT}
rotateEnabled={false}
style={styles.map}
showsUserLocation={true}
onRegionChangeComplete={handleRegionChange}
customMapStyle={mapStyle}
>
{AreasView}
</MapView>
I tried to get a ref for each Polygon but the number of callbacks is so high that makes the app crash. I also tried with ObservableAPI but with no success. Simplifying the polygons is not an option either. Is there any way to detect if each polygon is within the observable map to hide them when out of view? I been stuck for some days so far, I hope someone could help.
Thank you!
UPDATE
I have implemented a function that checks if a polygon is within boundaries on region change as such:
<MapView
...props
ref={mapRef}
onRegionChangeComplete={getMapBounds}
/>
const mapRef = useRef<MapView>(null);
const getMapBounds = async () => {
await mapRef?.current?.getMapBoundaries().then(res => setMapBounds(res));
};
This basically stores inside the state the northEast and southWest boundaries of the map every time the user changes view.
Then to check if is in view:
const isInView = useMemo(
() => (point: LatLng) => {
if (mapBounds) {
const { northEast, southWest } = mapBounds;
const x = point.longitude;
const y = point.latitude;
return (
northEast.latitude >= y &&
y >= southWest.latitude &&
northEast.longitude >= x &&
x >= southWest.longitude
);
}
},
[mapBounds]
);
Gets a portion of the polygon and checks is the latitude and longitude of the point are within those boundaries
And so this leaves to:
const AreasView = useMemo(
() =>
areas &&
areas.map((area: Area) => {
const coordinates = getCoordinates(area.geometry);
const areaColor = getAreaColor(area.status);
const isVisible = isInView(coordinates[0]);
if (isVisible) {
return (
<View key={area.CODE}>
<Polygon
strokeWidth={2}
fillColor={areaColor}
coordinates={coordinates}
strokeColor={areaColor}
tappable={true}
onPress={() => handlePressArea(area)}
/>
</View>
);
}
}),
[areas, isInView]
);
It's still quite slow...shall I use useCallback instead, or is it any function for any library that is more optimised than that?
Cheers

Multiple Polylines not rendering when cordinates array is updated

I am trying make a multi colored polyline. I have been able to do it successfully before with Vue.js but now we are adding it to react native app and its not working as i expected in React js.
I am making multiple polylines, each line (segment) has multiple points. I have a structure like this:
groups: [ { key: 'BLUE', cordinates: [] }, key: 'GREEN', cordinates: [] ];
Now each key represent a color and cordinates is an array of cordinates. Now when I loop it like this:
{
this.state.groups.map((group, index) => {
return (
<Polyline
key={index}
coordinates={group.Points}
strokeColor={
group.Key === "GREEN" ? "#0F0" : "#000"
// "#000"
// group.Key === "G"
} // 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}
/>
);
})
}
The problem is it works! perfectly but it doesnt draw the last polyline which is being updated. So for example there are 10 segments in this polyline. Now after 3 are drawn and loop is on 4th segment, its pushing each cordinate in the last group with a delay of 30 ms. I added delay to show it animated. Now it won't draw on map untill all cordinates of the 4th segments are pushed. When its done, and 5th segment is started, 4th segment shows perfectly but now 5th segment stops working.
I know that points are being perfectly added because I have added a Camera as well and I change its center to be last point that was pushed in groups/segments.
Group/Segments loop:
addPoint(group, point) {
var data = this.state.data;
if (group <= (data.length - 1)) {
var g = data[group];
// console.log('g', g);
if (point <= (g.Item2.length - 1)) {
var p = g.Item2[point];
var {groups} = this.state;
// console.log('groups,', groups);
groups[group].Points = groups[group].Points.concat({
longitude: p.longitude,
latitude: p.latitude,
});
this.MapView.animateCamera({
center: {
latitude: p.latitude,
longitude: p.longitude,
},
duration: 100,
zoom: 15,
});
point++;
setTimeout(() => {
this.addPoint(group, point);
}, 300);
} else {
point = 0;
group++;
if (group < this.state.data.length - 1) {
var key = this.state.data[group].Item1;
console.log('key', key);
var groups = this.state.groups.concat({
Key: key,
Points: [],
});
this.setState({
groups: groups,
})
}
setTimeout(() => {
this.addPoint(group, point);
}, 300);
}
} else {
console.log('last group reached');
}
}
Is there any solution for this?
I figured it out. The problem was whenever I updated the coordinates array of any polyline, it had to re-render whole thing which was performance wise very poor decision.
I solved it by making a custom polyline component which maintains its own coordinates array. Implemented an inner timeout function which pushes coordinates incrementally. This solved the problem and its now super easy to use.
You can read more about this here: multi colored gradient polyline using google maps on react native

Save Sketched lines in LocalStorage

Sorry im posting this here
I want to save the info of each line i drew on canvas(the save action would be called onChange)
so i can retrieve this data and draw it on canvas again in case the user change screen or something.
I'm using expo-pixi to draw a image and sketch over it
onChangeAsync = async (param) => {
// here i want on change code i get the line informantion and store it
}
onLayout = async ({
nativeEvent: {
layout: { width, height },
},
}) => {
this.setState({
layoutWidth: width,
layoutHeight: height,
})
this.onReady();
}
onReady = async () => {
const { layoutWidth, layoutHeight, points } = this.state;
this.sketch.graphics = new PIXI.Graphics();
if (this.sketch.stage) {
if (layoutWidth && layoutHeight) {
const background = await PIXI.Sprite.fromExpoAsync(this.props.image);
background.width = layoutWidth * scaleR;
background.height = layoutHeight * scaleR;
this.sketch.stage.addChild(background);
this.sketch.renderer._update();
}
}
};
// The sketch component is pretty much as the example which comes with the lib
<Sketch
ref={ref => (this.sketch = ref)}
style={styles.sketch}
strokeColor={this.state.strokeColor}
strokeWidth={this.state.strokeWidth}
strokeAlpha={1}
onChange={this.onChangeAsync}
onReady={this.onReady}
/>
Does anyone have any clue? im kind of desperate
Thanks

react-native-maps, rendering dynamic markers post run-time

Delete this question please, someone has helped me on another thread.
I am trying to generate markers at certain times in my app so that it will show a blank map at launch, but then sometime later, markers can show up and disappear at certain times.
My state variables are set up like this:
class Map extends Component {
state = {
markers: [{
key: null,
contactName: null,
location: null,
}]
}
The code I am trying to generate the markers with is as follows:
renderMarker = ({ key, contactName, location }) => {
console.log('renderMarker: ' + key + ', ' + contactName + ', ' + location);
return this.state.markers.map(Marker => (
<MapView.Marker
key = { key }
coordinate = {{
latitude: location[0],
longitude: location[1]
}}
//image = { carIcon }
title = { contactName } />
))
}
The console.log in there is generating the correct data, so it is returning for example:
renderMarker: 389djhJHDjdkh392sdk, Steve, -30.498767387,120.4398732
My render function looks like this:
render() {
return (
<MapContainer>
<MapView
style = { styles.map }
region = { this.state.mapRegion }
showsUserLocation = { true }
followUserLocation = { true }
onRegionChangeComplete = { this.onRegionChangeComplete.bind(this) }>
</MapView>
</MapContainer>
)
}
But nothing shows up on the map. I have been scouring the interwebs but I can't find a followable example. Do I need to add something to my render() function to make this work? My thoughts were I won't need to because renderMarker is doing that work.
Any ideas guys?