Skip to content

Instantly share code, notes, and snippets.

@Zerquix18
Created February 2, 2021 00:25
Show Gist options
  • Save Zerquix18/e3164483b7e2ecd3de39282e8a909826 to your computer and use it in GitHub Desktop.
Save Zerquix18/e3164483b7e2ecd3de39282e8a909826 to your computer and use it in GitHub Desktop.
import React, { useCallback, useEffect, useState } from 'react';
import { Button } from 'semantic-ui-react';
import { MapLatLng } from '../../../../../../../../../models';
import { computeDistanceBetween } from '../../../../../../../../../utils';
type Position = { date: Date; position: MapLatLng };
const MAX_POSITIONS = 3;
const Speedometer: React.FC = () => {
const [positions, setPositions] = useState<Position[]>([]);
const storePosition = useCallback(async (position: MapLatLng) => {
const date = new Date();
setPositions((positions) => {
if (positions.length >= MAX_POSITIONS) {
positions.shift();
}
positions.push({ position, date });
return positions;
});
}, []);
useEffect(() => {
const watchId = navigator.geolocation.watchPosition(position => {
const { coords: { latitude: lat, longitude: lng } } = position;
storePosition({ lat, lng });
}, () => {}, { enableHighAccuracy: true, maximumAge: 1000, timeout: 5000 });
return () => {
navigator.geolocation.clearWatch(watchId);
};
}, [storePosition]);
const speeds = positions.map((position, index, array) => {
const previous = array[index - 1];
if (! previous) {
return 0;
}
const time = (position.date.valueOf() / 1000) - (previous.date.valueOf() / 1000);
const distance = computeDistanceBetween(previous.position, position.position);
return distance / time;
});
const speed = speeds.length > 0 ? speeds.reduce((total, current) => total + current, 0) / speeds.length : 0;
return (
<Button circular>
{ (speed * 3.6).toFixed(2) } km/h
</Button>
);
};
export default Speedometer;
@Zerquix18
Copy link
Author

JS/class components:

import React from 'react';
import { Button } from 'semantic-ui-react';
import { computeDistanceBetween } from '../../../../../../../../../utils';

const MAX_POSITIONS = 3;

class Speedometer extends React.Component {
  state = {
    positions: []
  }

  componentDidMount = () => {
    this.watchId = navigator.geolocation.watchPosition(position => {
      const { coords: { latitude: lat, longitude: lng } } = position;
      this.storePosition({ lat, lng });
    }, () => {}, { enableHighAccuracy: true, maximumAge: 1000, timeout: 5000 });
  }

  componentWillUnmount = () => {
    navigator.geolocation.clearWatch(this.watchId);
  }

  storeLocation = (position) => {
    const date = new Date()

    this.setState(state => {
      positions = [...state.positions];
      if (positions.length >= MAX_POSITIONS) {
        positions.shift();
      }
      positions.push({ position, date });
      return { positions }
    });
  }

  render = () => {
    const { positions } = this.state;

    const speeds = positions.map((position, index, array) => {
      const previous = array[index - 1];
      if (! previous) {
        return 0;
      }
      const time = (position.date.valueOf() / 1000) - (previous.date.valueOf() / 1000);
      const distance = computeDistanceBetween(previous.position, position.position);
      return distance / time;
    });
  
    const speed = speeds.length > 0 ? speeds.reduce((total, current) => total + current, 0) / speeds.length : 0;
  
    return (
      <Button circular>
        { (speed * 3.6).toFixed(2) } km/h
      </Button>
    );
  }

}


export default Speedometer;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment