shootismoke/common

View on GitHub
packages/ui/src/util/station.ts

Summary

Maintainability
A
1 hr
Test Coverage
B
87%
// Sh**t! I Smoke
// Copyright (C) 2018-2021 Marcelo S. Coelho, Amaury M.
 
// Sh**t! I Smoke is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
 
// Sh**t! I Smoke is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
 
// You should have received a copy of the GNU General Public License
// along with Sh**t! I Smoke. If not, see <http://www.gnu.org/licenses/>.
 
import {
ACCURATE_RADIUS,
LatLng,
OpenAQResult,
} from '@shootismoke/dataproviders';
import haversine from 'haversine';
 
/**
* Capitalize a string.
*
* @param s - The string to capitalize
*/
export function capitalize(s: string): string {
return s.charAt(0).toUpperCase() + s.slice(1);
}
 
/**
* We can show distances in these two units.
*/
export type DistanceUnit = 'km' | 'mile';
 
/**
* Above this distance (km), we consider the station too far from the user
*/
export const MAX_DISTANCE_TO_STATION = ACCURATE_RADIUS / 1000;
 
/**
* Station given by the AQICN API is fucked up. Sometimes it's [lat, lng],
* sometimes it's [lng, lat].
* We check here with the user's real currentLocation coordinates, and take the
* "closest" one.
*
* @param currentLocation - An object containing {latitude, longitude}
* representing the user's current location.
* @param station - An object containing {latitude, longitude} representing
* the station's location.
*/
export function getCorrectLatLng(
currentLocation: LatLng,
station: LatLng
): LatLng {
Similar blocks of code found in 2 locations. Consider refactoring.
const d1 =
Math.abs(currentLocation.latitude - station.latitude) +
Math.abs(currentLocation.longitude - station.longitude);
 
Similar blocks of code found in 2 locations. Consider refactoring.
const d2 =
Math.abs(currentLocation.latitude - station.longitude) +
Math.abs(currentLocation.longitude - station.latitude);
 
if (d1 < d2) return station;
return {
...station,
latitude: station.longitude,
longitude: station.latitude,
};
}
 
/**
* Get distance from current location to station.
*
* @param currentLocation - The current location of the user.
* @param api - The api object returned by remote data.
* @param unit - The unit of measure returned.
*/
export function distanceToStation(
currentLocation: LatLng,
pm25Measurement: OpenAQResult,
unit: DistanceUnit = 'km'
): number {
// This case should be very rare, only happens on OpenAQ that sometimes,
// the `coordinates` field isn't returned. This field is actually optional
// in the OpenAQ format.
// FIXME Return something better than 0?
if (!pm25Measurement.coordinates) {
return 0;
}
 
return Math.round(
haversine(
currentLocation,
getCorrectLatLng(currentLocation, pm25Measurement.coordinates),
{ unit }
)
);
}
 
/**
* Returns true if the station is at more than {@link MAX_DISTANCE_TO_STATION}
* kilometers away from the current location.
*
* @param currentLocation - The current location of the user.
* @param api - The api object returned by remote data.
*/
export function isStationTooFar(
currentLocation: LatLng,
pm25Measurement: OpenAQResult
): boolean {
return (
distanceToStation(currentLocation, pm25Measurement) >
MAX_DISTANCE_TO_STATION
);
}