UNPKG

baqend

Version:

Baqend JavaScript SDK

151 lines (133 loc) 4.45 kB
import { JsonMap } from './util'; /** * Creates a new GeoPoint instance * From latitude and longitude * From a json object * Or an tuple of latitude and longitude */ export class GeoPoint { /** * How many radians fit in one degree. */ static readonly DEG_TO_RAD = Math.PI / 180; /** * The Earth radius in kilometers used by {@link GeoPoint#kilometersTo} */ static readonly EARTH_RADIUS_IN_KILOMETERS = 6371; /** * The Earth radius in miles used by {@link GeoPoint#milesTo} */ static readonly EARTH_RADIUS_IN_MILES = 3956; /** * Longitude of the given point */ public longitude: number; /** * Latitude of the given point */ public latitude: number; /** * Creates a GeoPoint with the user's current location, if available. * @return A promise that will be resolved with a GeoPoint */ static current(): Promise<GeoPoint> { return new Promise(((resolve, reject) => { if (!navigator) { reject(new Error('This seems not to be a browser context.')); } if (!navigator.geolocation) { reject(new Error('This browser does not support geolocation.')); } navigator.geolocation.getCurrentPosition((location) => { resolve(new GeoPoint(location.coords.latitude, location.coords.longitude)); }, (error) => { reject(error); }); })); } /** * @param latitude A coordinate pair (latitude first), * a GeoPoint like object or the GeoPoint's latitude * @param longitude The GeoPoint's longitude */ constructor(latitude?: number | string | { latitude: number, longitude: number } | [number, number], longitude?: number) { let lat: number; let lng: number; if (typeof latitude === 'string') { const index = latitude.indexOf(';'); lat = Number(latitude.substring(0, index)); lng = Number(latitude.substring(index + 1)); } else if (Array.isArray(latitude)) { [lat, lng] = latitude; } else if (typeof latitude === 'object') { lat = latitude.latitude; lng = latitude.longitude; } else { lat = typeof latitude === 'number' ? latitude : 0; lng = typeof longitude === 'number' ? longitude : 0; } this.longitude = lng; this.latitude = lat; if (this.latitude < -90 || this.latitude > 90) { throw new Error(`Latitude ${this.latitude} is not in bound of -90 <= latitude <= 90`); } if (this.longitude < -180 || this.longitude > 180) { throw new Error(`Longitude ${this.longitude} is not in bound of -180 <= longitude <= 180`); } } /** * Returns the distance from this GeoPoint to another in kilometers. * @param point another GeoPoint * @return The distance in kilometers * * @see GeoPoint#radiansTo */ kilometersTo(point: GeoPoint): number { return Number((GeoPoint.EARTH_RADIUS_IN_KILOMETERS * this.radiansTo(point)).toFixed(3)); } /** * Returns the distance from this GeoPoint to another in miles. * @param point another GeoPoint * @return The distance in miles * * @see GeoPoint#radiansTo */ milesTo(point: GeoPoint): number { return Number((GeoPoint.EARTH_RADIUS_IN_MILES * this.radiansTo(point)).toFixed(3)); } /** * Computes the arc, in radian, between two WGS-84 positions. * * The haversine formula implementation is taken from: * {@link http://www.movable-type.co.uk/scripts/latlong.html} * * Returns the distance from this GeoPoint to another in radians. * @param point another GeoPoint * @return the arc, in radian, between two WGS-84 positions * * @see http://en.wikipedia.org/wiki/Haversine_formula */ radiansTo(point: GeoPoint): number { const from = this; const to = point; const rad1 = from.latitude * GeoPoint.DEG_TO_RAD; const rad2 = to.latitude * GeoPoint.DEG_TO_RAD; const dLng = (to.longitude - from.longitude) * GeoPoint.DEG_TO_RAD; return Math.acos((Math.sin(rad1) * Math.sin(rad2)) + (Math.cos(rad1) * Math.cos(rad2) * Math.cos(dLng))); } /** * A String representation in latitude, longitude format * @return The string representation of this class */ toString(): string { return `${this.latitude};${this.longitude}`; } /** * Returns a JSON representation of the GeoPoint * @return A GeoJson object of this GeoPoint */ toJSON(): JsonMap { return { latitude: this.latitude, longitude: this.longitude }; } }