Untitled
unknown
plain_text
a year ago
18 kB
4
Indexable
import React, { useState, useEffect } from 'react'; import GPXReader from './GPXReader'; import MapView from './MapView'; import './css/Home.css'; function GeolocationTracker() { const [isCollecting, setIsCollecting] = useState(false); const [isCollectingFake, setIsCollectingFake] = useState(false); const [startTime, setStartTime] = useState(null); const [lastTime, setLastTime] = useState(null); const [distance, setDistance] = useState(0); const [startPosition, setStartPosition] = useState(null); const [lastPosition, setLastPosition] = useState(null); const [speed, setSpeed] = useState(0); const [accelerationY, setAccelerationY] = useState(0); const [accuracy, setAccuracy] = useState(null); const [isDriving, setIsDriving] = useState(false); const [currentTime, setCurrentTime] = useState(0); const [speedProfile, setSpeedProfile] = useState([]); const [fakePosition, setFakePosition] = useState([]); const [geojson, setGeojson] = useState(null); useEffect(() => { if (!isCollecting) return; const watchId = navigator.geolocation.watchPosition( (position) => { const currentTime = new Date().getTime(); if (!startTime) { setStartTime(currentTime); setLastTime(currentTime); setStartPosition({ latitude: position.coords.latitude, longitude: position.coords.longitude }); setLastPosition({ latitude: position.coords.latitude, longitude: position.coords.longitude }); } else { const deltaTime = (currentTime - lastTime) / 1000; // elapsed time in seconds const currentDistance = calculateDistance(lastPosition.latitude, lastPosition.longitude, position.coords.latitude, position.coords.longitude); setDistance((prevDistance) => prevDistance + currentDistance); const currentSpeed = currentDistance / deltaTime; // current speed in m/s setSpeed(currentSpeed); setLastTime(currentTime); setLastPosition({ latitude: position.coords.latitude, longitude: position.coords.longitude }); setSpeedProfile((prevProfile) => [ ...prevProfile, { time: (currentTime - startTime) / 1000, speed: currentSpeed, distance: distance + currentDistance } ]); } setAccuracy(position.coords.accuracy); setIsDriving(position.coords.speed > 0.1); // Assuming speed > 0.1 m/s indicates driving }, (error) => { console.error('Error getting geolocation:', error); }, { maximumAge: 0, enableHighAccuracy: true } ); const handleMotionEvent = (event) => { setAccelerationY(event.accelerationIncludingGravity.y); }; window.addEventListener('devicemotion', handleMotionEvent); const intervalId = setInterval(() => { setCurrentTime((new Date().getTime() - startTime) / 1000); }, 1000); return () => { clearInterval(intervalId); navigator.geolocation.clearWatch(watchId); window.removeEventListener('devicemotion', handleMotionEvent); }; }, [isCollecting, startTime, lastTime, distance, lastPosition]); // Function to calculate distance between two coordinates const calculateDistance = (lat1, lon1, lat2, lon2) => { // Haversine formula const R = 6371e3; // metres const φ1 = (lat1 * Math.PI) / 180; // φ, λ in radians const φ2 = (lat2 * Math.PI) / 180; const Δφ = ((lat2 - lat1) * Math.PI) / 180; const Δλ = ((lon2 - lon1) * Math.PI) / 180; const a = Math.sin(Δφ / 2) * Math.sin(Δφ / 2) + Math.cos(φ1) * Math.cos(φ2) * Math.sin(Δλ / 2) * Math.sin(Δλ / 2); const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); return R * c; // in meters }; const clearData = () => { setIsCollecting(false); setStartTime(null); setLastTime(null); setDistance(0); setStartPosition(null); setLastPosition(null); setSpeed(0); setAccelerationY(0); setAccuracy(null); setIsDriving(false); setCurrentTime(0); setSpeedProfile([]); }; const restartCollecting = () => { setIsCollecting(true); setStartTime(null); setLastTime(null); setDistance(0); setStartPosition(null); setLastPosition(null); setSpeed(0); setAccelerationY(0); setAccuracy(null); setIsDriving(false); setCurrentTime(0); setSpeedProfile([]); }; useEffect(() => { if (!isCollectingFake) return; const fakeRideInterval = setInterval(() => { const currentTime = new Date().getTime(); if (!startTime) { setStartTime(currentTime); setLastTime(currentTime); const initialPosition = { latitude: 0, longitude: 0 }; // Set initial fake position setStartPosition(initialPosition); setLastPosition(initialPosition); setFakePosition([initialPosition]); } else { const deltaTime = (currentTime - lastTime) / 1000; // elapsed time in seconds const fakeLastPosition = lastPosition || { latitude: 0, longitude: 0 }; const fakeCurrentPosition = { latitude: fakeLastPosition.latitude + 0.0001, // Simulate movement longitude: fakeLastPosition.longitude + 0.0001 }; const currentDistance = calculateDistance(fakeLastPosition.latitude, fakeLastPosition.longitude, fakeCurrentPosition.latitude, fakeCurrentPosition.longitude); setDistance((prevDistance) => prevDistance + currentDistance); const currentSpeed = currentDistance / deltaTime; // current speed in m/s setSpeed(currentSpeed); setLastTime(currentTime); setLastPosition(fakeCurrentPosition); setSpeedProfile((prevProfile) => [ ...prevProfile, { time: (currentTime - startTime) / 1000, speed: currentSpeed, distance: distance + currentDistance } ]); setFakePosition((prevPositions) => [ ...prevPositions, fakeCurrentPosition ]); } setAccuracy(5); // Set a fixed accuracy for fake data setIsDriving(true); // Assuming always driving in fake mode }, 1000); return () => { clearInterval(fakeRideInterval); }; }, [isCollectingFake, startTime, lastTime, distance, lastPosition]); // Function to get speed profile by seconds const getSpeedProfileBySeconds = () => { const profileBySeconds = {}; speedProfile.forEach(entry => { const second = Math.floor(entry.time); if (!profileBySeconds[second]) { profileBySeconds[second] = { speed: 0, distance: 0 }; } profileBySeconds[second] = { speed: entry.speed, distance: entry.distance }; }); return profileBySeconds; }; // Component to display speed table const Table = ({ profileBySeconds, maxSeconds }) => ( <div style={styles.tableContainer}> <div className="customScrollbar" style={styles.tableScroll}> <table style={styles.speedTable}> <thead> <tr> <th style={{borderBottom: '0px solid ', padding: '10px',textAlign: 'center',verticalAlign: 'top'}}>Speed profile seconds</th> <th style={styles.th}>km/h</th> <th style={{borderBottom: '0px solid ', padding: '10px',textAlign: 'center',verticalAlign: 'top'}}>m</th> </tr> </thead> <tbody> {Array.from({ length: maxSeconds }).map((_, index) => { const second = index + 1; const entry = profileBySeconds[second] || { speed: 0, distance: 0 }; const speedKmh = entry.speed * 3.6; // Convert from m/s to km/h const speedMph = speedKmh * 0.621371; // Convert from km/h to mph return ( <tr key={second}> <td style={{ padding: '10px', borderBottom: '0px solid', textAlign: 'center', verticalAlign: 'top' }}>{second}</td> <td style={styles.td}>{speedKmh.toFixed(2)}</td> <td style={styles.td}>{speedMph.toFixed(2)}</td> </tr> ); })} </tbody> </table> </div> </div> ); const profileBySeconds = getSpeedProfileBySeconds(); const maxSeconds = Math.max(...Object.keys(profileBySeconds).map(key => parseInt(key, 10))); const handleGPXLoad = (data) => { setGeojson(data); }; return ( <div style={{ display: 'flex', justifyContent: 'center'}}> {/*{!isCollecting ? <div style={{ marginRight: '20px' }}> /!* Add margin-right to create space *!/*/} {/* <GPXReader onGPXLoad={handleGPXLoad} />*/} {/* {geojson && <MapView geojson={geojson} currentSpeed={speed} />}*/} {/*</div> : null}*/} <div style={{ }}> {/* Add margin-left to create space */} <div className="container" style={styles.container}> <h2 style={{ color: 'white' }}>Speed Coach</h2> <table style={styles.table}> <tbody> <tr style={styles.row}> <td style={styles.label}>State:</td> <td style={styles.data}>{isDriving ? 'Driving' : 'Standing'}</td> </tr> <tr style={styles.row}> <td style={styles.label}>GPS Speed:</td> <td style={styles.data}>{(speed * 3.6).toFixed(2)} km/h</td> </tr> <tr style={styles.row}> <td style={styles.label}>Y Acceleration:</td> <td style={styles.data}>{accelerationY.toFixed(2)}</td> </tr> <tr style={styles.row}> <td style={styles.label}>GPS Accuracy:</td> <td style={styles.data}>{accuracy ? `${accuracy} meters` : 'N/A'}</td> </tr> <tr style={styles.row}> <td style={styles.label}>Distance from start:</td> <td style={styles.data}>{distance.toFixed(0)} meters</td> </tr> </tbody> </table> <div style={styles.tableContainer}> <div style={styles.tableScroll}> <table style={styles.speedTable}> <th style={{borderBottom: '0px solid ', padding: '10px',textAlign: 'center',verticalAlign: 'top'}}>Speed profile seconds</th> <th style={styles.th}>km/h</th> <th style={{borderBottom: '0px solid ', padding: '10px',textAlign: 'center',verticalAlign: 'top'}}>m</th> <tbody> {Array.from({ length: maxSeconds }).map((_, index) => { const second = index + 1; const entry = profileBySeconds[second] || { speed: 0, distance: 0 }; const speedKmh = entry.speed * 3.6; // Convert from m/s to km/h const speedMph = speedKmh * 0.621371; // Convert from km/h to mph return ( <tr key={second}> <td style={{ padding: '10px', borderBottom: '0px solid', textAlign: 'center', verticalAlign: 'top' }}>{second}</td> <td style={styles.td}>{speedKmh.toFixed(2)}</td> <td style={styles.td}>{speedMph.toFixed(2)}</td> </tr> ); })} </tbody> </table> </div> </div> </div> <div style={{ display: 'flex', justifyContent: 'space-between', position: 'relative', bottom: 0, left: 0, right: 0 }}> <button style={styles.button} onClick={isCollecting ? clearData : restartCollecting}> {isCollecting ? 'Clear' : 'Restart'} </button> {/*<button style={{ backgroundColor: 'transparent',*/} {/* color: 'transparent',*/} {/* border: 'none',*/} {/* cursor: 'pointer',*/} {/* fontWeight: 'bold',*/} {/* justifyContent: 'center',marginLeft:10}}>*/} {/* {isCollectingFake ? 'Fake ride stop' : 'Fake ride start'}*/} {/*</button>*/} <button style={{ backgroundColor: '#70309f', color: '#fff', border: 'none', cursor: 'pointer', fontWeight: 'bold', justifyContent: 'center',marginLeft:10}} onClick={() => setIsCollectingFake(!isCollectingFake)}> {isCollectingFake ? 'Fake ride stop' : 'Fake ride start'} </button> </div> </div> </div> ); }; const styles = { overlay: { // justifyContent: 'center', // alignItems: 'center', // flexDirection: 'column', // color: 'white', // height: '100%', // width:'300', // marginTop: 40, // display:'flex-center' }, container: { backgroundColor: 'rgba(38,38,38,255)', padding: '2px', borderRadius: '8px', width: '100%', maxWidth: '400px', textAlign: 'center', marginBottom: '20px', margin: '20px auto' }, button_container: { padding: '20px', borderRadius: '8px', width: '90%', maxWidth: '400px', textAlign: 'center', marginBottom: '20px', }, table: { width: '100%', borderCollapse: 'collapse', marginBottom: '20px', color: 'white', }, row: { borderBottom: '1px solid rgba(0, 0, 0, 0.1)', }, label: { textAlign: 'left', padding: '10px', fontWeight: 'bold', }, data: { textAlign: 'right', padding: '10px', }, buttonContainer: { display: 'flex', justifyContent: 'flex-end', }, button: { backgroundColor: '#70309f', color: '#fff', border: 'none', cursor: 'pointer', fontWeight: 'bold', position: 'absolute', bottom: 0, right: 0, marginTop:'10px' }, listViewContainer: { width: '90%', maxWidth: '400px', backgroundColor: 'rgba(38,38,38,255)', padding: '20px', borderRadius: '8px', textAlign: 'center', color: 'white', height: '150px', overflowY: 'auto', // Add this line position: 'relative', // Add this line }, listViewHeader: { display: 'flex', top: '0', // Add this line backgroundColor: 'rgba(38,38,38,255)', // Add this line padding: '10px 0', // Add this line justifyContent: 'space-between', overflow:'false' }, listView: { display: 'flex', }, tableContainer: { backgroundColor: 'rgba(38,38,38,255)', paddingTop: '5px', borderRadius: '8px', width: '90%', maxWidth: '400px', textAlign: 'right', marginBottom: '20px', color: 'white', }, tableScroll: { maxHeight: '200px', overflowY: 'auto', // paddingRight: '10px', // Add padding to the right to create space between the scrollbar and table }, speedTable: { width: '100%', borderCollapse: 'collapse', }, th: { borderBottom: '0px solid ', padding: '10px', textAlign: 'start', // Align text to the left verticalAlign: 'top', // Align text to the top }, td: { padding: '10px', borderBottom: '0px solid ', textAlign: 'left', // Align text to the left verticalAlign: 'top', // Align text to the top }, }; export default GeolocationTracker;
Editor is loading...
Leave a Comment