40 lines
1.5 KiB
TypeScript
40 lines
1.5 KiB
TypeScript
/**
|
|||
|
|
* [Gitea #340] Helpers for the "Share location" confirm step: the geo URI to
|
||
|
|
* send (RFC 5870, with the fix's accuracy as `u=` so receivers can draw a
|
||
|
|
* radius) and a human accuracy label, so a ±3 km Wi-Fi/IP fix isn't presented
|
||
|
|
* — or sent — as if it were exact.
|
||
|
|
*/
|
||
|
|
|
||
|
|
/** Decimals kept for an "approximate" share: 2 → ~1.1 km of latitude. */
|
||
|
|
export const APPROXIMATE_DECIMALS = 2;
|
||
|
|
/** Uncertainty reported for an approximate share (half a 0.01° cell, rounded up). */
|
||
|
|
export const APPROXIMATE_UNCERTAINTY_M = 1000;
|
||
|
|
|
||
|
|
const validAccuracy = (accuracy?: number): number | undefined =>
|
||
|
|
typeof accuracy === 'number' && Number.isFinite(accuracy) && accuracy > 0
|
||
|
|
? Math.round(accuracy)
|
||
|
|
: undefined;
|
||
|
|
|
||
|
|
export const buildGeoUri = (
|
||
|
|
latitude: number,
|
||
|
|
longitude: number,
|
||
|
|
accuracy?: number,
|
||
|
|
approximate = false,
|
||
|
|
): string => {
|
||
|
|
const decimals = approximate ? APPROXIMATE_DECIMALS : 6;
|
||
|
|
const u = approximate
|
||
|
|
? Math.max(APPROXIMATE_UNCERTAINTY_M, validAccuracy(accuracy) ?? 0)
|
||
|
|
: validAccuracy(accuracy);
|
||
|
|
const base = `geo:${latitude.toFixed(decimals)},${longitude.toFixed(decimals)}`;
|
||
|
|
return u ? `${base};u=${u}` : base;
|
||
|
|
};
|
||
|
|
|
||
|
|
/** "±12 m", "±3.5 km", or undefined when the browser gave no accuracy. */
|
||
|
|
export const formatAccuracy = (accuracy?: number): string | undefined => {
|
||
|
|
const m = validAccuracy(accuracy);
|
||
|
|
if (m === undefined) return undefined;
|
||
|
|
if (m < 1000) return `±${m} m`;
|
||
|
|
const km = m / 1000;
|
||
|
|
return `±${km < 10 ? km.toFixed(1) : Math.round(km)} km`;
|
||
|
|
};
|