Skip to content

Instantly share code, notes, and snippets.

@tkh44
Last active August 29, 2015 14:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tkh44/4bd07918f48514c94a36 to your computer and use it in GitHub Desktop.
Save tkh44/4bd07918f48514c94a36 to your computer and use it in GitHub Desktop.
location caching and distance checking
((angular, window) => {
/**
* GeoLocation Utility Service
* @param $localStorage
* @param $cordovaGeolocation
* @param $q
* @returns {{getCachedGeoLocation: getCachedGeoLocation, getDistance: getDistance}}
* @constructor
*/
var GeoService = function($localStorage, $cordovaGeolocation, $q) {
var $storage = $localStorage,
cachedLocation = $storage.currentLocation,
isUS = navigator.language.match(/us/ig);
// Was the last lookup more than 5 min ago and did it contain an error.
var isLocationExpired = () =>
angular.isUndefined(cachedLocation) // Is there a cachedLocation object
|| !cachedLocation.error // Error from device
|| cachedLocation.timestamp - Date.now() > 3E5; // Older than 300000ms(5 min)
/**
* Return the distance in miles if `navigator.language` is 'en-US' otherwise
* returns distance in kilometers
*
* @param {number} distance
* @returns {string} distance in either miles or km
*/
var getLocaleDistance = (distance) =>
isUS ? (distance / 1.609344).toFixed(1) + ' mi' : distance.toFixed(1) + ' km';
/**
* Calculates the distance between two latitude-longitude points
*
* Taken from {@link http://stackoverflow.com/a/7179026}
* @param {number} lat1
* @param {number} lon1
* @param {number} lat2
* @param {number} lon2
* @returns {number}
*/
var computeDistanceBetween = (lat1, lon1, lat2, lon2) => {
var toRad = (val) => val * Math.PI / 180;
var R = 6371 | 0, // Radius of the earth 6371 km
dLat = toRad(lat2 - lat1),
dLon = toRad(lon2 - lon1);
var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(toRad(lat1)) * Math.cos(toRad(lat2)) * Math.sin(dLon / 2) * Math.sin(dLon / 2);
var c = 2 * Math.atan(Math.sqrt(a), Math.sqrt(1 - a));
return R * c;
};
/**
* Storage for deferred variable.
*
* @type {null}
*/
var deferred = null;
/**
* Get the user's last known location.
* Checks cache(localStorage) before making call to device.
*
* @returns {external:Promise}
*/
this.getCachedGeoLocation = function() {
if (_.isNull(deferred)) {
deferred = $q.defer();
// Pull from cache
if (!isLocationExpired()) {
return $q.when(cachedLocation);
// Pull from device
} else {
$cordovaGeolocation.getCurrentPosition().then((position) => {
var currentPosition = {
latitude: position.coords.latitude,
longitude: position.coords.longitude,
accuracy: position.coords.accuracy ,
timestamp: +position.timestamp
};
$storage.currentLocation = currentPosition;
deferred.resolve(currentPosition);
}, (err) => {
cachedLocation['error'] = err;
deferred.reject(err)
}).finally(() => {
deferred = null;
});
}
}
return deferred.promise;
};
/**
* Get the distance of the building from the cached geolocation of user
*
* @param {number} latitude
* @param {number} longitude
* @returns {string} prettyDistance
*/
this.getDistance = function(latitude, longitude) {
return getLocaleDistance(computeDistanceBetween(cachedLocation.latitude, cachedLocation.longitude, latitude, longitude));
}
};
angular.module('iOffice.geo', ['ngCordova']).service('GeoService', GeoService);
})(angular, window);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment