/**************************************************************************************************************** * CLASS geoLocation: helper-class for fetching geolocation (among others latitude, longitude) * * implemented as singleton-object * * * * methods: init(void):void --> initialize object and start fetching position * * startWatcher(void):void --> starts intervalled position-watching (ran by init) * * getPosFromServer(void):void --> fetch GPS-position from server (actually one fixed point) * * distance(Object{lat:Number ,lon:Number} [,Object{lat:Number ,lon:Number}]):Number * * └-> distance between two positions (or given and current one, if second one missing) * * * * events: body.geoLocationError:Object{ * * error:Object{ * * number:Number, * * message:String * * }, * * position:Object{ * * latitude:Number, * * longitude:Number, * * accuracy:Number, * * timestamp:Number * * } * * } * * body.geoLocationGot:Object{ * * position:Object{ * * latitude:Number, * * longitude:Number, * * accuracy:Number, * * timestamp:Number * * } * * } * ****************************************************************************************************************/ var geoLocation = { // implement as singleton latitude: null, longitude: null, accuracy: null, timestamp: null, _pwatcher: null, _ptimer: null, _disableWatcherAt: 50, _config: { enableHighAccuracy: true, maximumAge: 10000, // 10 sec max cache lifetime (if geoposition cached) timeout: 60000 // 60 sec timeout }, // event listeners _geoReady: function(position) { console.debug('geolocation api present - activate watcher'); // this.startWatcher(); // this._gotLocation(position); }, _geoError: function(error) { console.debug('gelocation api not present or error'); this._handle_error(error); }, _gotLocation: function(position) { this.latitude = position.coords.latitude; this.longitude = position.coords.longitude; this.accuracy = position.coords.accuracy; this.timestamp = position.timestamp; if (this.accuracy <= this._disableWatcherAt) // disable with timeout, if accurate location found { console.debug('disable watcher for 60 seconds', this._pwatcher); if (this._pwatcher !== null) { console.debug('watcher cleared'); navigator.geolocation.clearWatch(this._pwatcher); this._pwatcher = null; } that = this; this._ptimer = setTimeout(function() {that.startWatcher.apply(that, arguments);}, 60000); } console.debug('got Position: ' + this.latitude + ', ' + this.longitude + '(' + this.accuracy + 'm < ' + this._disableWatcherAt + ': ' + (this.accuracy <= this._disableWatcherAt) + ')'); $('body').trigger('geoLocationGot', {'position':{latitude: this.latitude, longitude: this.longitude, accuracy: this.accuracy, timestamp: this.timestamp}}); }, _handle_error: function(error) { console.debug(error); switch(error.code) { case error.PERMISSION_DENIED: if (_pwatcher != 'null') navigator.geolocation.clearWatch(_pwatcher); _pwatcher = 'null'; break; case error.POSITION_UNAVAILABLE: break; case error.TIMEOUT: break; default: break; } $('body').trigger('geoLocationError',{'error':error,'position':{latitude: this.latitude, longitude: this.longitude, accuracy: this.accuracy, timestamp: this.timestamp}}); }, init: function() { var that = this; if (navigator.geolocation) { console.debug('test geolocation api'); navigator.geolocation.getCurrentPosition( function() {that._geoReady.apply(that, arguments);}, function() {that._geoError.apply(that, arguments);}, this._config ); } }, startWatcher: function() { console.debug('waiting for location'); that = this; if (this._pwatcher !== null) navigator.geolocation.clearWatch(this._pwatcher); clearTimeout(this._ptimer); this._pwatcher = navigator.geolocation.watchPosition( function() {that._gotLocation.apply(that, arguments);}, function() {that._handle_error.apply(that, arguments);}, this._config ); console.debug('watcher started',this._pwatcher); }, getPosFromServer: function() { console.debug('get position from server'); that = this; $.getJSON('shippos.php', function(data) { console.debug('got server response: ',data); that._gotLocation.call(that, data); }); }, //haversine formula for distance between two positions in m (see http://www.movable-type.co.uk/scripts/latlong.html) distance:function(c1,c2) { PI180=Math.PI / 180; if(!c1) return false; if(!c2){ c2={'latitude':this.latitude, 'longitude':this.longitude}; } var dLat = (c2.latitude-c1.latitude) * PI180; // delta in rad var dLon = (c2.longitude-c1.longitude) * PI180; var lat1 = c1.latitude * PI180; var lat2 = c2.latitude * PI180; var a = Math.sin(dLat/2) * Math.sin(dLat/2) + Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(lat1) * Math.cos(lat2); var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); return (6371000 * c); // earth-radius in m * 1000 } }; // geoLocation $(document).ready(function() { $('body').on('geoLocationGot', function(e) { $('#no-gps').slideUp({duration: 500}); }); $('body').on('geoLocationError',function(e) { $('#no-gps').slideDown({duration: 500}); }); geoLocation.init(); });