Set the bounds of a mapView - react-native

I have an app that calls an api and returns a list of locations.
Once the data is returned, I convert the JSON to map points for annotations.
These get added to the ma with no problem.
The problem I am running into is setting the bounds of the map. I can't seem to figure it out.
The code I currently have is.
_handleResponse(response) {
var locations = [];
// Loop through repsone and add items to an arra for annotations
for (var i = 0; i < response.length; i++) {
// Get the location
var location = response[i];
// Parse the co ords
var lat = parseFloat(location.Latitude);
var lng = parseFloat(location.Longitude);
// Add the location to array
locations.push({
latitude: lat,
longitude: lng,
title: location.Name
});
}
// This calls the map set state
this.setState({
annotations: locations
});
}
and here is my view code
<View style={styles.container}>
<MapView
style={styles.map}
onRegionChangeComplete={this._onRegionChangeComplete}
annotations={this.state.annotations}
/>
</View>

You'll want
<MapView
...
region={region}
/>
where
var region = {
latitude,
longitude,
latitudeDelta,
longitudeDelta,
};
latitude and longitude are the center of the map and the deltas are the distance (in degrees) between the minimum and maximum lat/long shown. For instance, given a certain radius in miles around a point and an aspect ratio of the map view, you could calculate region as follows:
var radiusInRad = radiusInKM / earthRadiusInKM;
var longitudeDelta = rad2deg(radiusInRad / Math.cos(deg2rad(latitude)));
var latitudeDelta = aspectRatio * rad2deg(radiusInRad);
The definitions of rad2deg, deg2rad, and earthRadiusInKM are left as an exercise to the reader.

Here is my complete code based on #Philipp's answer:
import React, { Component } from 'react';
import { MapView } from 'react-native';
const earthRadiusInKM = 6371;
// you can customize these two values based on your needs
const radiusInKM = 1;
const aspectRatio = 1;
class Map extends Component {
constructor(props) {
super(props);
// this will be the map's initial region
this.state = {
region : {
latitude: 0,
longitude: 0
}
};
}
// you need to invoke this method to update your map's region.
showRegion(locationCoords) {
if (locationCoords && locationCoords.latitude && locationCoords.longitude) {
var radiusInRad = radiusInKM / earthRadiusInKM;
var longitudeDelta = this.rad2deg(radiusInRad / Math.cos(this.deg2rad(locationCoords.latitude)));
var latitudeDelta = aspectRatio * this.rad2deg(radiusInRad);
this.setState({
region: { latitude: locationCoords.latitude, longitude: locationCoords.longitude, latitudeDelta: latitudeDelta, longitudeDelta: longitudeDelta }
});
}
}
render () {
return (
<MapView
style={{flex: 1}}
region={this.state.region}/>
)
}
deg2rad (angle) {
return angle * 0.017453292519943295 // (angle / 180) * Math.PI;
}
rad2deg (angle) {
return angle * 57.29577951308232 // angle / Math.PI * 180
}
}

Related

Maps cannot load when the screen is moving too fast

I have a list of points that are the coordinates of the journey.
It runs normally when I use a vehicle marker run on the map with a duration of 500 ms.
But when I used animateToRegion to make the map follow the vehicle, problems started to happen:
Normally, map needs about 1second to load. So when use animateToRegion with duration is 500 ms. Map hasn't downloaded yet. ( as the right of image )
const intervalRef = useInterval(
() => {
if (timerRef.current < data.length - 1) {
setTimer(timer => timer + 1);
timerRef.current += 1;
} else {
window.clearInterval(intervalRef.current);
if (timerRef.current === data.length - 1) {
setPlayed(false);
}
}
},
isPlayed ? timeDuration : null,
);
// timer update per timeDuration = 500ms
useEffect(() => {
animateMarker();
mapRef?.current?.animateToRegion({
latitude: data[timer].Lt,
longitude: data[timer].Ln,
latitudeDelta: SUP_LATITUDE_DELTA,
longitudeDelta: SUP_LONGITUDE_DELTA,
});
}, [timer]);
const animateMarker = () => {
const newCoordinate = {
latitude: data[timer].Lt,
longitude: data[timer].Ln,
latitudeDelta: SUP_LATITUDE_DELTA,
longitudeDelta: SUP_LONGITUDE_DELTA,
};
if (Platform.OS === 'android') {
if (marker) {
marker.animateMarkerToCoordinate(
newCoordinate,
timer == 0 ? 0 : timeDuration,
);
}
} else {
coordinate.timing(newCoordinate).start();
}
};
Video demo
So does someone have any solutions for it?

Can't resolve 'three' in three-gltf-loader

This is the first time that I cannot find an answer and have to write here. I am trying a three.js project with Vue.js. I have this error:
Failed to compile.
./node_modules/three-gltf-loader/index.js
Module not found: Error: Can't resolve 'three' in 'C:\Users\Skunk\Documents\dolfin\dolfin\node_modules\three-gltf-loader'
My code:
import * as THREE from 'three-js';
import GLTFLoader from 'three-gltf-loader';
export default {
name: 'HelloWorld',
props: {
msg: String
},
mounted(){
let scene = new THREE.Scene( );
let camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerWidth / window.innerHeight, 0.1, 1000);
let renderer = new THREE.WebGLRenderer( );
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
window.addEventListener( 'resize', function( )
{
let width = window.innerWidth;
let height = window.innerHeight;
renderer.setSize( width, height);
camera.aspect = width / height;
camera.updateProjectionMatrix( );
} );
const loader = new GLTFLoader();
// Load a glTF resource
loader.load(
// resource URL
'models/dol.gltf',
// called when the resource is loaded
function ( gltf ) {
scene.add( gltf.scene );
gltf.animations; // Array<THREE.AnimationClip>
gltf.scene; // THREE.Group
gltf.scenes; // Array<THREE.Group>
gltf.cameras; // Array<THREE.Camera>
gltf.asset; // Object
},
// called while loading is progressing
function ( xhr ) {
console.log( ( xhr.loaded / xhr.total * 100 ) + '% loaded' );
}
);
camera.position.z = 3;
//let ambientLight = new THREE.AmbientLight( 0xFFFFFF, 0.8);
// scene.add( ambientLight );
// game logic
let update = function ( )
{};
// draw scene
let render = function( )
{
renderer.render( scene, camera );
};
// run game loop
let GameLoop = function( )
{
requestAnimationFrame( GameLoop );
update( );
render( );
};
GameLoop( );
}
}
Am I using pieces of code that are not compatible?
For starters, you should not be using the "three-js" node module. This is a really outdated version of Three that got stuck on r79 and hasn't been updated in 4 years. Instead, you should be using the official "three" node module, which is the legitimate library, and is currently on r124.
Second, just import the GLTF loader from the "three/examples" folder as demonstrated in the GLTF examples, instead of installing a whole new module.
import * as THREE from "three";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
const loader = new GLTFLoader();

Drawing polygon on react native maps

I'm using react-native-maps. Is there any way to draw a polygon and get coordinates of vertices in react-native-maps?
Here's the snippet from my code
import MapView, { PROVIDER_GOOGLE, Marker } from "react-native-maps";
render:
{directions && (
<MapView.Polyline coordinates={directions} strokeWidth={4} />
)}
I am using this function to get the polyline:
export const getDirections = async (pickup, dropoff) => {
let response = await callMapsAPI(pickup, dropoff)
// console.log("Cords of direction res: ", response);
if (response) {
// let respJson = await response.json();
// console.log("Cords of direction res json: ", respJson);
let points = Polyline.decode(response.data.routes[0].overview_polyline.points);
// console.log("Cords of direction res points: ", points);
let coords = points.map((point, index) => {
return {
latitude: point[0],
longitude: point[1]
}
})
return coords
} else return null
}
Where
import Polyline from '#mapbox/polyline';
For React Native, you can use
using PanResponder to track x y and convert to latitude and longitude. You can view it here: https://github.com/dev-event/react-native-maps-draw

Dividing react-native Animated.Values

I want to produce an Animated.Value that is the result of dividing a constant by another Animated.Value.
const originalSize = 255;
const currentSize = this.props.someAnimatedValue;
// This method doesn't exist, but it's what I want:
const animatedScaleFactor = Animated.divide(originalSize, currentSize);
```
Since there is no Animated.divide() method, I only have at my disposal someAnimatedValue.interpolate(), which I can use to map an input range to an output range with a custom easing curve, Animated.multiply(), and Animated.modulus().
Any ideas?
UPDATE - use Animated.Divide instead.
Old answer:
Figured out how to get what I want f(x) = 1/x using an interpolator and custom easing function:
import React, {
Animated,
Component,
View
} from 'react-native';
export default class EasingTest extends Component {
state = {
input: new Animated.Value(0)
};
componentDidMount() {
const max = 937;
const output = this.state.input.interpolate({
inputRange: [0,max],
outputRange: [0,1/max],
easing: t => 1 / t
});
setInterval(() => {
const input = this.state.input.__getValue();
const expected = 1 / input;
const actual = output.__getValue();
const error = Math.abs(expected - actual) / max;
console.info(`f(${input}) = ${actual} (expected ${expected}, error ${Math.round(error * 100)}%`);
}, 200);
Animated.timing(this.state.input, {
toValue: max,
duration: 1000
}).start();
}
render() {
return <View />
}
}

Showing multiple markers on map : Titanium

I am making an app in which i have to show Map in my Application.
I am able to show map and able to add Markers using annotation on Mapview.
Problem is
1> I am not able to show multiple markers on map.
So any body can help me how i can add multiple markers on Map.
Thanks,
Rakesh
Here is a map class that I use. You would include this map.js file in your window and call map.init and pass in an array of map annotations to add, the center lat/long, the top and bottom positions of the map, and optionally the lat/long delta. If you want to dynamically add annotations after the map has already been created then you can call the other functions in the class to do so:
var path = Ti.Platform.name == 'android' ? Ti.Filesystem.resourcesDirectory : "../../";
var map = {
top: 0,
bottom: 0,
latitude: 0,
longitude: 0,
latitudeDelta: 0.1,
longitudeDelta: 0.1,
display: "map",
init: function (annotations, latitude, longitude, top, bottom, delta) {
if (top)
map.top = top;
if (bottom)
map.bottom = bottom;
if (delta) {
map.latitudeDelta = delta;
map.longitudeDelta = delta;
}
map.createMap(annotations, latitude, longitude);
map.createOptions();
map.getLocation();
},
createMap: function (annotations, latitude, longitude) {
map.mapView = Ti.Map.createView({
mapType: Ti.Map.STANDARD_TYPE, animate: true, regionFit: false, userLocation: true,
region: { latitude: latitude, longitude: longitude, latitudeDelta: map.latitudeDelta, longitudeDelta: map.longitudeDelta },
annotations: annotations, bottom: map.bottom, top: map.top, borderWidth: 1
});
if (!isAndroid) {
map.mapView.addAnnotation(annotations[0]);
}
map.mapView.selectAnnotation(annotations[0]);
win.add(map.mapView);
},
createOptions: function () {
//map/satellite displays.
var mapDisplay = new ImageView({ image: path + 'images/map/satellite-view.png', width: 70, height: 49, zIndex: 2, top: map.top + 5, right: 5 });
mapDisplay.addEventListener('click', function () {
if (map.display == "map") {
map.mapView.setMapType(Titanium.Map.SATELLITE_TYPE);
mapDisplay.image = path + "images/map/map-view.png";
map.display = "satellite";
}
else {
map.mapView.setMapType(Titanium.Map.STANDARD_TYPE);
mapDisplay.image = path + "images/map/satellite-view.png";
map.display = "map";
}
});
win.add(mapDisplay);
//crosshairs.
if(Ti.Geolocation.locationServicesEnabled) {
var centerDisplay = new ImageView({ image: path + 'images/map/crosshairs.png', width: 49, height: 49, zIndex: 2, top: map.top + 5, right: 80 });
centerDisplay.addEventListener('click', function () {
if(map.latitude != 0 && map.longitude != 0) {
info("setting user location to " + map.latitude + " / " + map.longitude);
//center map.
var userLocation = {
latitude: map.latitude,
longitude: map.longitude,
latitudeDelta: map.latitudeDelta,
longitudeDelta: map.longitudeDelta,
animate: true
};
map.mapView.setLocation(userLocation);
}
else {
info("Can't get user location, lat and long is 0!");
}
});
win.add(centerDisplay);
}
},
createAnnotation: function (title, subtitle, latitude, longitude, isLocation, addToMap) {
var mapAnnotation = Ti.Map.createAnnotation({
latitude: latitude, longitude: longitude,
title: title,
subtitle: subtitle,
animate: true
});
if (isAndroid) {
mapAnnotation.pinImage = path + (isLocation ? "images/map/blue-pin.png" : "images/map/purple-pin.png");
}
else {
mapAnnotation.pincolor = isLocation ? Ti.Map.ANNOTATION_PURPLE : Ti.Map.ANNOTATION_RED;
}
if (addToMap)
map.mapView.addAnnotation(mapAnnotation);
return mapAnnotation;
},
updateAnnotation: function (mapAnnotation, title, subtitle, latitude, longitude, isLocation) {
if (mapAnnotation) {
map.mapView.removeAnnotation(mapAnnotation);
mapAnnotation = map.createAnnotation(title, subtitle, latitude, longitude, isLocation);
map.mapView.addAnnotation(mapAnnotation);
map.mapView.selectAnnotation(mapAnnotation);
}
},
addAnnotation: function (mapAnnotation) {
map.mapView.addAnnotation(mapAnnotation);
},
removeAnnotation: function (mapAnnotation) {
map.mapView.removeAnnotation(mapAnnotation);
},
selectAnnotation: function (mapAnnotation) {
map.mapView.selectAnnotation(mapAnnotation);
},
createRoute: function (name, points) {
var route = {
name: name, points: points, color: "#7c74d4", width: 4
};
map.mapView.addRoute(route);
setTimeout(function () { map.mapView.regionFit = true; }, 700);
},
getLocation: function() {
Ti.Geolocation.preferredProvider = Ti.Geolocation.PROVIDER_GPS;
Ti.Geolocation.purpose = "testing";
Ti.Geolocation.accuracy = Ti.Geolocation.ACCURACY_BEST;
Ti.Geolocation.distanceFilter = 10;
if(!Ti.Geolocation.locationServicesEnabled) {
//alert('Your device has GPS turned off. Please turn it on.');
return;
}
function updatePosition(e) {
if(!e.success || e.error) {
info("Unable to get your location - " + e.error);
return;
}
info(JSON.stringify(e.coords));
map.latitude = e.coords.latitude;
map.longitude = e.coords.longitude;
Ti.Geolocation.removeEventListener('location', updatePosition);
};
Ti.Geolocation.getCurrentPosition(updatePosition);
Ti.Geolocation.addEventListener('location', updatePosition);
}
};