Untitled

 avatar
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