import React, { useState, useEffect, Component } from 'react'; import * as Location from 'expo-location'; import { Text, View } from './components/Themed'; import { StyleSheet } from 'react-native'; import * as geolib from 'geolib'; var debug:number = 0; var testCount = 0; var bgEnabled:boolean = false; var expoGeoState:any = null; export var locEnabled:boolean = false; const heartbeat:number = 500; const displayBeat:number = 3; const geoLibAccuracy:number = 0.1; const minExpoAccuracy:number = 10; const styles = StyleSheet.create({ tripText: { marginHorizontal: -10, marginVertical: 60, textAlign: 'left', width: "80%", fontSize: 12, fontWeight: 'bold', }}); interface expoGeoObj { coords: [ altitude:number, altitudeAccuracy:number, latitude:number, accuracy:number, longitude:number, heading:number, speed:number, timestamp:number ] } class Coordinate { public mLatitude:number = 0.0; public mLongitude:number = 0.0; public glCoords:any = {}; constructor (latitude:number, longitude:number ) { this.mLongitude = longitude; this.mLatitude = latitude; this.get_glcoords(); } public set(lat:number,lon:number) { this.mLatitude = lat; this.mLongitude = lon; this.get_glcoords(); } public get_glcoords() { this.glCoords['lat'] = this.mLatitude; this.glCoords['lon'] = this.mLongitude; } public distanceTo(otherPoint:Coordinate) : number { return geolib.getPreciseDistance(this.glCoords,otherPoint.glCoords,geoLibAccuracy); } } async function startTracking(client:any){ if (debug > 5) console.log('Starting tracking') if(!client.location){ client.location = await Location.watchPositionAsync({ accuracy: Location.Accuracy.Highest, distanceInterval: 3, timeInterval: (heartbeat / 2), }, (loc) => { Trips.deltaLoc(loc) }); } } async function stopTracking(client:any){ if (debug > 5) console.log('Remove tracking') await client.location.remove(); } class Trip { public elapsed:string = "00.00.00"; ticks:number = 0; interval:any; segments:number = 1; ds:number = 0; CO2:number = 0.0; location:any = null; lastDSFixTick = 0; lastFix:Coordinate = new Coordinate(0.0,0.0); loc:Coordinate = new Coordinate(0.0,0.0); tick() {let hours:number = 0, minutes:number = 0, seconds:number = 0, totals:number = 0; this.ticks++; totals = this.ticks * ( heartbeat / 1000 ) ; hours = totals < 3600 ? 0 : (totals / 3600); minutes = totals < 60 ? 0 : (totals - (hours * 3600)) / 60; seconds = totals % 60; this.elapsed = hours.toFixed(0) + ":" + minutes.toFixed(0) + ":" + seconds.toFixed(0); } public start() { this.interval = setInterval(() => this.tick(), heartbeat); if (!bgEnabled) startTracking(this); } public resume() { this.lastFix.mLatitude = 0.0; this.segments++; this.interval = setInterval(() => this.tick(), heartbeat); } public stop() { Trips.distance += this.ds; this.ds = 0.0; clearInterval(this.interval); if (!bgEnabled) stopTracking(this); } } export class GT2 { trip:Trip = new Trip(); endPoint:Coordinate = new Coordinate(0.0,0.0); startPoint:Coordinate = new Coordinate(0.0,0.0); displayInterval:number = displayBeat * heartbeat; public distance:number = 0.0; co2Rate:number = 250.0; z:number = 0.0; public v:number = 0.0; public inProgress:boolean = false; public paused:boolean = false; public elapsed:number = 0.0; elevation:number = 0.0; public units:string = "km"; public CO2Effect:string = "carbon burden"; nTrips:number = 0; n:number = 0.0; m:number = 0.0; public deltaLoc(lastFix:any) { var t:number = 0.0; lastFix = JSON.stringify(lastFix); let expoFix:expoGeoObj = JSON.parse(lastFix); if (debug > 10) { console.log("lat " + expoFix.coords['latitude'] + " lon " + expoFix.coords['longitude']); console.log("heading " + expoFix.coords['heading']); console.log("accuracy " + expoFix.coords['accuracy']); console.log("speed " + expoFix.coords['speed']); } this.trip.loc.set(expoFix.coords['latitude'],expoFix.coords['longitude']); if (Trips.startPoint.mLatitude == 0.0) Trips.startPoint.set(this.trip.loc.mLatitude,this.trip.loc.mLongitude); t = expoFix.coords['accuracy']; if (t < minExpoAccuracy ) return; if (this.trip.lastFix.mLatitude == 0.0) this.trip.lastFix.set(this.trip.loc.mLatitude,this.trip.loc.mLongitude); else {this.trip.ds += this.trip.lastFix.distanceTo(this.trip.loc); this.trip.lastFix.set(this.trip.loc.mLatitude,this.trip.loc.mLongitude); if (debug > 10) console.log('delta ' + this.trip.ds); } } public end() { this.trip.stop(); this.inProgress = false; if (this.distance < 250) this.distance = 0; this.trip.CO2 = ( this.distance / 1000 ) * this.co2Rate; this.nTrips++; } public setLocEnabled(value:boolean) { locEnabled = value} public pause() { if (!this.paused) { this.trip.stop(); this.paused = true; } else { this.trip.resume(); this.paused = false; } } public reset() { this.distance = 0.0; this.endPoint = new Coordinate(0,0); this.startPoint = new Coordinate(0,0); this.v = 0; this.inProgress = false; this.paused = false; this.elapsed = 0.0; } public start() { this.reset(); this.trip = new Trip(); this.trip.start(); this.inProgress = true; } lt:number = 0.0; public getTripSummary() : string { var preferredUnits:number = ((this.units == 'km') ? (this.distance / 1000) : (this.distance / 1609.34)); return ( 'Elapsed - ' + this.trip.elapsed + '\n' + 'Origin: ' + 'lat: ' + this.trip.loc.mLatitude.toFixed(8) + ' long: ' + this.trip.loc.mLongitude.toFixed(8) + '\n' + 'Destination: ' + 'lat: ' + this.trip.loc.mLatitude.toFixed(8) + ' long: ' + this.trip.loc.mLongitude.toFixed(8) + '\n' + 'CO2: ' + this.trip.CO2.toFixed(1) + ' grams ' + this.CO2Effect + '\n\n' + 'Distance covered while consuming fuel: ' + preferredUnits.toFixed(2) + ' ' + this.units ); } public getTripPanel() : string { var bigDS:number = this.distance + this.trip.ds; var seconds:number = this.trip.ticks; if (this.inProgress) { this.v = this.trip.ds / seconds; return ( 'Elapsed - ' + this.trip.elapsed + '\n' + 'Geo: ' + 'lat: ' + this.trip.loc.mLatitude.toFixed(8) + ' long: ' + this.trip.loc.mLongitude.toFixed(8) + '\n' + 'Vector: ' + 'distance: ' + bigDS.toFixed(2) + ' meters, velocity: ' + this.v.toFixed(1) + ' m/s \n' + 'Altitude: ' + this.elevation + '\n'); } else return("No trip in progress. " + this.nTrips + " trip(s) completed."); } } export class TripDisplay extends React.Component { constructor(props:any) { super(props); this.state = { seconds: 0 }; } interval:any; tick() { this.setState(state => ({ seconds: 1 })); } componentDidMount() { this.interval = setInterval(() => this.tick(), Trips.displayInterval); } componentWillUnmount() { clearInterval(this.interval); } render() { if (debug > 10) return( {Trips.getTripPanel() } ); else; return( {Trips.getTripPanel() } {expoGeoState} ); } } export class TripSummary extends React.Component { handleRefresh = () => { // by calling this method react re-renders the component this.setState({}); }; render() { return( {Trips.getTripSummary() } ); } } export var Trips:GT2 = new GT2();