mirror of
https://github.com/owntracks/frontend.git
synced 2026-08-21 11:16:17 +00:00
119 lines
3.4 KiB
JavaScript
119 lines
3.4 KiB
JavaScript
import moment from "moment";
|
|
|
|
import config from "@/config";
|
|
import { DATE_TIME_FORMAT, EARTH_RADIUS_IN_KM } from "@/constants";
|
|
|
|
/**
|
|
* Get a complete URL for any API resource, taking the
|
|
* base URL configuration into account.
|
|
*
|
|
* @param {String} path Path to the API resource
|
|
* @returns {URL} Final API URL
|
|
*/
|
|
export const getApiUrl = (path) => {
|
|
const normalizedBaseUrl = config.api.baseUrl.endsWith("/")
|
|
? config.api.baseUrl.slice(0, -1)
|
|
: config.api.baseUrl;
|
|
const normalizedPath = path.startsWith("/") ? path : `/${path}`;
|
|
return new URL(`${normalizedBaseUrl}${normalizedPath}`);
|
|
};
|
|
|
|
/**
|
|
* Check if the given string is an ISO 8601 YYYY-MM-DDTHH:MM:SS datetime.
|
|
*
|
|
* @param {String} s Input value to be tested
|
|
* @returns {Boolean} Whether the input matches the expected format
|
|
*/
|
|
export const isIsoDateTime = (s) => moment(s, DATE_TIME_FORMAT, true).isValid();
|
|
|
|
/**
|
|
* Convert degrees to radians.
|
|
*
|
|
* @param {Number} degrees Angle in degrees
|
|
* @returns {Number} Angle in radians
|
|
*/
|
|
export const degreesToRadians = (degrees) => (degrees * Math.PI) / 180;
|
|
|
|
/**
|
|
* Calculate the distance between two coordinates. Uses the haversine formula,
|
|
* which is not 100% accurate - but that's not the goal here.
|
|
*
|
|
* https://en.wikipedia.org/wiki/Haversine_formula
|
|
*
|
|
* @param {Coordinate} c1 First coordinate
|
|
* @param {Coordinate} c2 Second coordinate
|
|
* @returns {Number} Distance in meters
|
|
*/
|
|
export const distanceBetweenCoordinates = (c1, c2) => {
|
|
const r = EARTH_RADIUS_IN_KM * 1000;
|
|
const phi1 = degreesToRadians(c1.lat);
|
|
const phi2 = degreesToRadians(c2.lat);
|
|
const lambda1 = degreesToRadians(c1.lng);
|
|
const lambda2 = degreesToRadians(c2.lng);
|
|
const d =
|
|
2 *
|
|
r *
|
|
Math.asin(
|
|
Math.sqrt(
|
|
Math.sin((phi2 - phi1) / 2) ** 2 +
|
|
Math.cos(phi1) *
|
|
Math.cos(phi2) *
|
|
Math.sin((lambda2 - lambda1) / 2) ** 2
|
|
)
|
|
);
|
|
return d;
|
|
};
|
|
|
|
/**
|
|
* Let the user download a string as file.
|
|
*
|
|
* @param {String} text Content of the file
|
|
* @param {String} filename Suggested filename for the browser
|
|
* @param {String} [mimeType] Content mime type
|
|
*/
|
|
export const download = (text, filename, mimeType = "text/plain") => {
|
|
const dataUrl = `data:${mimeType},${encodeURIComponent(text)}`;
|
|
const element = document.createElement("a");
|
|
element.href = dataUrl;
|
|
element.download = filename;
|
|
element.style.display = "none";
|
|
document.body.appendChild(element);
|
|
element.click();
|
|
document.body.removeChild(element);
|
|
};
|
|
|
|
/**
|
|
* Format a distance in meters into a human-readable string with unit.
|
|
*
|
|
* This only supports m / km for now, but could read a config option and return
|
|
* ft / mi.
|
|
*
|
|
* @param {Number} distance Distance in meters
|
|
* @returns {String} Formatted string including unit
|
|
*/
|
|
export const humanReadableDistance = (distance) => {
|
|
let unit = "m";
|
|
if (Math.abs(distance) >= 1000) {
|
|
distance = distance / 1000;
|
|
unit = "km";
|
|
}
|
|
return `${distance.toLocaleString(config.locale, {
|
|
maximumFractionDigits: 1,
|
|
})} ${unit}`;
|
|
};
|
|
|
|
/**
|
|
* Get the total number of locations from a nested location history.
|
|
*
|
|
* @param {LocationHistory} locationHistory Location history
|
|
* @returns {Number} Total number of locations
|
|
*/
|
|
export const getLocationHistoryCount = (locationHistory) =>
|
|
Object.keys(locationHistory)
|
|
.map((user) =>
|
|
Object.keys(locationHistory[user])
|
|
.map((device) => locationHistory[user][device].length)
|
|
.reduce((a, b) => a + b, 0)
|
|
)
|
|
.reduce((a, b) => a + b, 0);
|