Repository

js/Mobilizing/input/GPS.js

import * as debug from '../core/util/Debug';
import Component from '../core/Component';

/**
* Fired when the location has been updated
* @event locationupdated
*/
const EVT_LOC_UPDATED = "locationupdated";

/**
* Fired when the location update generated an error
* @event locationerror
*/
const EVT_LOC_ERROR = "locationerror";

export default class GPS extends Component {
    /**
    * @param {Object} params Parameters object, given by the constructor.
    * @param {Boolean} params.enableHighAccuracy Boolean to activate accurate location (eats more battery and takes time)
    * @param {Number} params.maximumAge Number of millisecond to define the maximum age of the geolocation data (default = 500000)
    * @param {Number} params.timeout timeout of the location service in millisecond
    */
    constructor({
        enableHighAccuracy = false,
        maximumAge = undefined,
        timeout = undefined,
    } = {}) {
        super(...arguments);

        this.enableHighAccuracy = enableHighAccuracy;
        this.maximumAge = maximumAge;
        this.timeout = timeout;

        /**
        * true if the GPS is available on the device, false otherwise
        * @type {Boolean}
        */
        this.available = (navigator !== undefined) && ("geolocation" in navigator);
    }

    /**
    * Set the GPS up.
    */
    setup() {
        if (!this._setupDone) {
            /**
            * Object containing the informations given by the GPS. Used internally.
            * @property {Object} _location
            * @private
            */
            this.location = {
                latitude: null,
                longitude: null,
                altitude: null,
                accuracy: null,
                altitudeAccuracy: null,
                heading: null,
                speed: null,
                timestamp: null
            };
            super.setup();
        }
    }

    /**
    * Activates the component
    */
    on() {
        if (this.available) {
            super.on();

            const positionOptions = {
                enableHighAccuracy: this.enableHighAccuracy,
                timeout: this.timeout,
                maximumAge: this.maximumAge
            };

            this._watchID = navigator.geolocation.watchPosition((event) => this.updateLocationCallBack(event), (event) => this.updateLocationErrorCallBack(event), positionOptions);
        }
        else {
            debug.info("this device has no GPS!");
        }
    }

    /**
    * Deactivate the component
    */
    off() {
        super.off();

        navigator.geolocation.clearWatch(this._watchID);
    }

    /**
    * returns the most recent location data. Location service MUST be activated on the device, or errors will get out from the callbacks!
    * The return objects contains the standard HTML5 properties for geolocation :
    *
    *     location.longitude
    *     location.latitude
    *     location.altitude
    *     location.accuracy
    *     location.altitudeAccuracy
    *     location.heading
    *     location.speed
    *     location.timestamp
    *
    * @return {Object} the location object updated with the most recent data.
    */
    getLocation() {
        if (this.active) {
            return this.location;
        }

        debug.warn("geolocation is off, turn it on!");

        return null;
    }

    /**
    * Listener for the update of the location object with the most recent data.
    *
    * @param {Object} position the HTML5 position object to use for the Mobilizing location object's update
    * @private
    */
    updateLocationCallBack(position) {
        //debug.log(position);
        this.location.longitude = position.coords.longitude;
        this.location.latitude = position.coords.latitude;
        this.location.altitude = position.coords.altitude;
        this.location.accuracy = position.coords.accuracy;
        this.location.altitudeAccuracy = position.coords.altitudeAccuracy;
        this.location.heading = position.coords.heading;
        this.location.speed = position.coords.speed;
        this.location.timestamp = position.timestamp;
        this.location.error = "no error";

        this.events.trigger(EVT_LOC_UPDATED, this.location);
    }

    /**
    * Listener for the update errors of the location object with the most recent data.
    *
    * @param error
    * @private
    */
    updateLocationErrorCallBack(error) {
        if (error.code === 1) {
            console.error("location permission denied");
            this.location.error = "location permission denied";

        }
        else if (error.code === 2) {
            console.error("location unavailable");
            this.location.error = "location unavailable";

        }
        else if (error.code === 3) {
            console.error("location timeout");
            this.location.error = "location timeout";
        }

        this.events.trigger(EVT_LOC_ERROR, this.location.error);
    }

    /**
    * reset the location object to avoid bugs
    * @private
    * @deprecated
    */
    resetLocation() {
        this.location = {
            latitude: null,
            longitude: null,
            altitude: null,
            accuracy: null,
            altitudeAccuracy: null,
            heading: null,
            speed: null,
            timestamp: null
        };
    }
}