Here map integration in react-native mobile app - react-native

I am trying to implement heremap api in react-native project.While searching got https://www.npmjs.com/package/react-native-heremaps .But there is no proper documents to use this library. I am new to react-native. Please give me some suggestions to implement this.

! if you don't use expo please comment and I'll change the answer a bit !
First of all, as you probably know you need to make an account at HERE Developer webiste.
After you have made an account, you have to create a project(you can get a Freemium plan for free and it has plenty of requests available for free, upgrade if you need more). After that you need to "Generate App" for REST & XYZ HUB API/CLI at your project page. With that, you will recieve APP ID and APP CODE. With all this, HERE Developer Account setup is complete.
Lets jump to React Native now.
First of all you need to install a npm package called react-native-maps which we will use to display data that HERE provides. You can see installation instructions here.
After this, lets assume you have already created a component that will show the map. You need to import this:
import { Marker, Polyline } from 'react-native-maps'
import { MapView } from 'expo'
With that we have our map almost ready.
I will use axios in this example but you can use fetch to make requests to HERE if you want.
So we import axios(if you never worked with it you can learn more about it here):
import axios from 'axios'
Now, you should have coordinates of those two locations ready in a state or somewhere, and it should look something like this:
constructor(props){
super(props)
this.state = {
startingLocation: {
latitude: "xx.x",
longitude: "yy.y",
},
finishLocation: {
latitude: "xx.x",
longitude: "yy.y",
}
}
}
With "xx.x" and "yy.y" being actual coordinates you want.
So now when you have coordinates of start and finish location you can make a request to you HERE API project. It's as easy as this(I got this api from here):
// I will create a function which will call this, you can call it whenever you want
_getRoute = () => {
// we are using parseFloat() because HERE API expects a float
let from_lat = parseFloat(this.state.startingLocation.latitude)
let from_long = parseFloat(this.state.startingLocation.longitude)
let to_lat = parseFloat(this.state.finishLocation.latitude)
let to_long = parseFloat(this.state.finishLocation.longitude)
// we will save all Polyline coordinates in this array
let route_coordinates = []
axios.get(`https://route.api.here.com/routing/7.2/calculateroute.json?app_id=PUT_YOUR_APP_ID_HERE&app_code=PUT_YOUR_APP_CODE_HERE&waypoint0=geo!${from_lat},${from_long}&waypoint1=geo!${to_lat},${to_long}&mode=fastest;bicycle;traffic:disabled&legAttributes=shape`).then(res => {
// here we are getting all route coordinates from API response
res.data.response.route[0].leg[0].shape.map(m => {
// here we are getting latitude and longitude in seperate variables because HERE sends it together, but we
// need it seperate for <Polyline/>
let latlong = m.split(',');
let latitude = parseFloat(latlong[0]);
let longitude = parseFloat(latlong[1]);
routeCoordinates.push({latitude: latitude, longitude: longitude});
}
this.setState({
routeForMap: routeCoordinates,
// here we can access route summary which will show us how long does it take to pass the route, distance etc.
summary: res.data.response.route[0].summary,
// NOTE just add this 'isLoading' field now, I'll explain it later
isLoading: false,
})
}).catch(err => {
console.log(err)
})
}
NOTE There are few things to note here. First is that you have to replace APP ID and APP CODE with acutal APP ID and APP CODE from your HERE project.
Second note that I added &legAttributes=shape at the end of the request URL but it is not in the documentation. I put it there so Polyline coordinates acutally have a correct shape, if you don't put it, it will just respond with coordinates of road turns and that polyline will go over buildings and stuff, it will just look bad.
OK. So now we have coordinates to make a Polyline, let's do that.
<MapView>
<Polyline coordinates={this.state.routeForMap} strokeWidth={7} strokeColor="red" geodesic={true}/>
<Marker coordinate={{latitude: this.state.startingLocation.latitude, longitude: this.state.startingLocation.longitude}} title="Starting location"/>
<Marker coordinate={{latitude: this.state.finishLocation.latitude, longitude: this.state.finishLocation.longitude}} title="Finishlocation"/>
</MapView>
Explanation:
Polyline.coordinates will map through all of the coordinates that we have provided and draw a Polyline. strokeWidth is just how thick you want your line to be, and strokeColor is obviously color of a line.
Now, you should add a region to your MapView component to let it know what is the initial region you want to show on the map. So I suggest you to do something like this:
In state, define a region field and make it the same coordinates as starting location, and then set delta to make a bit larger view.
// so in state just add this
region: {
latitude: parseFloat("xx.x"),
longitude: parseFloat("yy.y"),
latitudeDelta: 0.0922,
longitudeDelta: 0.0421,
}
And now, add region={this.state.region} to MapView.
You would be done now, but let's make sure this works every time. You need to make sure that HERE API request is complete before the map renders. I would do it like this:
// in your state define field to control if loading is finished
isLoading: true,
Now, you would call the function _getRoute() we made before in componendDidMount() lifecycle function provided by React Native. Like this:
componentDidMount() {
// when this function is finished, we will set isLoading state to false to let program know that API request has finished and now we can render the map
this._getRoute()
}
So finally a final step is to control isLoading in your render() function:
render() {
if(this.state.isLoading) {
return (
<Text>Loading...(you could also use <ActivityIndicator/> or what ever you want to show while loading the request)</Text>
)
} else {
// just put everything we already did here + stuff you already have
}
}
So here it is. I tried to make it as detailed as possible to make it easy for you and other people that will need help with this.
Don't ever hesitate to ask me anything if something is unclear or it's not working or you need more help! I'm always happy to help :D

Related

In React Native / Expo, is there any way to save a specific part of an image?

From some research, I've figured out that expo libraries like takePicturesAsync() are able to take a picture and save it to the app's cache. However, the default state for libraries like these is to save the whole image. Is there any way for me to save a specific part of the image (e.g. the 2500 pixels at the center of the screen)?
Thanks!
You can use the onPictureSaved event to grab & manipulate the image.
takePicture = () => {
if (this.camera) {
this.camera.takePictureAsync({ onPictureSaved: this.onPictureSaved });
}
};
onPictureSaved = photo => {
console.log(photo);
}

React Native (Track user on following direction (Google Map))

React Native;
How we can Monitor The google map Tracking So Actually User drive on line or not, E.g.
if i got the direction from Location A to Location B , So how we can check that User Drive on Line or not.
Basically i can't Monitor it,
E.g
Actually i want it in react native,
So anyOne Help me How we can achieve it or any 3rd party Library,
Thanks in Advance.
This Method isPointNearLine is Solve my problem.
Code Snippet.
import * as geolib from 'geolib';
const returnObj=(lat,lon)=>{
return {
latitude: lat, longitude:lon
}
}
const IsLies = geolib.isPointNearLine(
returnObj(25.976424, -80.238400), ////point
returnObj(25.97641, -80.24045), ////start
returnObj(25.97647,-80.23818), ///end
20 ////distance in meter
);
it will return true and false.
There is another approach is we can user #turf/boolean-point-on-line
Code Snippet
var pt = turf.point([74.276089,31.478847]); //// NearPoint
///Note [[Start Point],[NearPoint],[EndPoint]]
var line = turf.lineString([[74.277908,31.479470],[74.276089,31.478847],[74.274402,31.478452]]);
var isPointOnLine = turf.booleanPointOnLine(pt, line);
it will also return True and false if Points lies on line.

React Native expo-location: How to make the background location service update more often?

I'm building a sports app with Expo / React Native and trying to figure out a good way to track user location while the app is in the background. I have built a solution with expo-location (https://docs.expo.io/versions/latest/sdk/location/#locationstartlocationupdatesasynctaskname-options) which successfully receives location updates, and I even managed to send the location updates to the UI with the help of an EventEmitter.
Now the problem here is, the Expo Location task keeps the location updates deferred for a VERY long time (like 12 minutes) before sending a location update to the UI. This is despite setting all the relevant options to zero or very small.
I would love to use Expo Location because I got it mostly working, but unbelievably it seems that the library lacks an option/tool to force the background task to send updates often enough (like once in 5 seconds).
I would be grateful if anyone had a solution to really making the Expo background location send updates often enough. Now it sends updates "when I feel like it", about once in 5 or 12 minutes, despite setting all the relevant options and parameters I found in the documentation.
I already came to the conclusion that Expo background location is practically broken and I should switch to another location library (https://github.com/mauron85/react-native-background-geolocation). However I'm using Expo managed workflow and installing this mauron85 location library (otherwise really promising) doesn't work, because it requires setting manually dependencies --> I need to eject from Expo managed workflow --> ejecting breaks my project structure in a way I don't know how to solve. Really frustrating!
Relevant parts of my code:
top part:
import * as Location from 'expo-location';
import * as TaskManager from 'expo-task-manager';
import EventEmitter from 'EventEmitter'
const locationEmitter = new EventEmitter();
const BACKGROUND_LOCATION_TRACKER = 'BACKGROUND_LOCATION_TRACKER'
const LOCATION_UPDATE = 'LOCATION_UPDATE'
componentDidMount after requesting location permissions:
await Location.startLocationUpdatesAsync(BACKGROUND_LOCATION_TRACKER, {
accuracy: LocationAccuracy.BestForNavigation,
timeInterval: 0, // all set to 0 to make it update as often as possible!!! doesn't help
distanceInterval: 0,
deferredUpdatesInterval: 0,
deferredUpdatesDistance: 0,
showsBackgroundLocationIndicator: true,
foregroundService: {
notificationTitle: 'title',
notificationBody: 'recording',
notificationColor: '#008000',
},
// pausesUpdatesAutomatically: true,
});
locationEmitter.on(LOCATION_UPDATE, (locationData) => {
console.log('locationEmitter locationUpdate fired! locationData: ', locationData);
let coordinatesAmount = locationData.newRouteCoordinates.length - 1;
this.setState({
latitude: locationData.newRouteCoordinates[coordinatesAmount - 1].latitude,
longitude: locationData.newRouteCoordinates[coordinatesAmount - 1].longitude,
routeCoordinates: this.state.routeCoordinates.concat(locationData.newRouteCoordinates)
})
})
define location task:
TaskManager.defineTask(BACKGROUND_LOCATION_TRACKER, async ({ data, error }) => {
if (error) {
console.error(error);
return;
}
if (data) {
const { locations } = data;
console.log('backgroundLocationTracker received new locations: ', locations)
// const [location] = locations;
const locationsLength = locations.length;
const newRouteCoordinates = [];
// const totalNewDistance = 0.0;
for (i = 0; i < locationsLength; i++) {
const { latitude, longitude } = locations[i].coords;
const tempCoords = {
latitude,
longitude,
};
newRouteCoordinates.push(tempCoords);
// totalNewDistance += GLOBAL.screen1.calcDistance(newRouteCoordinates[i], newRouteCoordinates[i - 1])
};
console.log('backgroundLocationTracker: latitude ', locations[locationsLength - 1].coords.latitude,
', longitude: ', locations[locationsLength - 1].coords.longitude, ', routeCoordinates: ', newRouteCoordinates,
', prevLatLng: ', newRouteCoordinates[locationsLength - 1]);
let locationData = { newRouteCoordinates }
locationEmitter.emit(LOCATION_UPDATE, locationData)
}
});
As I said, it all WORKS (!) in the sense that I do get location updates from the background to the UI. The only problem here is that I can't figure out how to make the background task send location updates more often! It just keeps collecting a huge batch of 50+ location updates for even 10+ minutes before it bothers to send them to the UI!
All help appreciated, thanks.
I thought I would have to eject from expo too, but I changed my options and now it updates just as I intended.
The problem was the acuracy, I switched to "best for navigation" just as your example and it worked.
Here is my options, I think you should try to define some milisseconds, don't leave interval at 0 and don't set distance interval nor defered distance:
{accuracy: Location.Accuracy.BestForNavigation,
timeInterval: 1000,
showsBackgroundLocationIndicator: true,
foregroundService:{
notificationTitle: "Covid Tracker",
notificationBody: "Rastreando sua localização",
notificationColor: "#AA1111"
},
deferredUpdatesInterval: 100
}

react-native-video only play first few seconds of video

Anyone knows how to only play the first few seconds, and repeat it in a react-native video?
I have a profile page which displays all the videos of the user. Currently its playing the whole video but i only want the first few seconds (something like Tiktok).
If you want to just loop the first seconds, just add an onProgress and send back to starting second when it passes a certain second:
class Video extends Component {
render() {
const {source, YOUR_VARIABLE_FOR_SECONDS} = this.props;
return <VideoPlayer
source={source}
ref={(ref) => {
this.player = ref
}}
onProgress={({currentTime}) => {
if (currentTime > YOUR_VARIABLE_FOR_SECONDS) {
this.player.seek(0)
}
}}
/>
}
}
There is no sense in doing it that way. Probably TikTok takes the "five seconds" and transforms it into GIF using something like a GIFIFY (https://github.com/jclem/gifify). If someone asked me to do this, I would certainly do so.
EDIT:
I think that you can create a code/component that displays only the X seconds, I think its possible

How to make <Polyline /> follow roads in react-native-maps with HERE API

I was able to make the request to HERE API and get the response, I put all the waypoints from leg to an array(latitude and longitude) and it does draw a polyline but it does not follow the road. It just goes trough buildings etc.
This is my Polyline component:
<Polyline coordinates={this.state.route} strokeWidth={7} strokeColor="#2ecc71" geodesic={true} />
this.state.route is an array of coordinates which I got like this:
axios.get(`https://route.api.here.com/routing/7.2/calculateroute.json?app_id={myappid}&app_code={myappcode}&waypoint0=geo!${from_lat},${from_long}&waypoint1=geo!${to_lat},${to_long}&mode=fastest;bicycle;traffic:disabled`).then((response) => {
console.log(response.data.response.route);
response.data.response.route[0].leg[0].maneuver.map((m) => {
routeCoordinates.push({latitude: m.position.latitude, longitude: m.position.longitude});
})
console.log(routeCoordinates);
this.props.navigation.navigate('ShowMap', {
spot: chosenSpot,
route: routeCoordinates,
});
}).catch((error) => {
console.log(error);
})
And then I pass this array to my screen and put it in my state as route.
I expect it to draw a polyline over roads and not over buildings and stuff.
Here is an image to show you how it looks like(NOTE that blue lines are just to cover road names it has nothing to do with drawing a polyline):
Please add an additional parameter to the calculateroute rest api:
legAttributes=shape
Then the rest api will return shape object containing the points along the roads.
https://route.api.here.com/routing/7.2/calculateroute.json?app_id={myappid}&app_code={myappcode}&waypoint0=geo!${from_lat},${from_long}&waypoint1=geo!${to_lat},${to_long}&mode=fastest;bicycle;traffic:disabled&legAttributes=shape
Please see legAttributes in the documentation.
https://developer.here.com/documentation/routing/topics/resource-calculate-route.html