Fork me on GitHub
Show:

File: ../src/geolocate/html5geolocateservice.js

define([
  'aeris/util',
  'aeris/promise',
  'aeris/geolocate/options/html5serviceoptions',
  'aeris/geolocate/results/geolocateposition',
  'aeris/geolocate/errors/geolocateserviceerror'
], function(_, Promise, HTML5ServiceOptions, GeolocatePosition, GeolocateServiceError) {
  var root = this;

  /**
   * @publicApi
   * @class aeris.geolocate.HTML5GeolocateService
   * @implements aeris.geolocate.GeolocateServiceInterface
   *
   * @constructor
   * @override
   *
   * @param {aeris.geolocate.options.HTML5ServiceOptions=} opt_options
   */
  var HTML5GeolocateService = function(opt_options) {
    var options = new HTML5ServiceOptions(opt_options);

    /**
     * @type {Object}
     * @property navigatorOptions_
     */
    this.navigatorOptions_ = _.pick(options,
      'enableHighAccuracy',
      'maximumAge',
      'timeout'
    );


    /**
     * @type {Navigator} HTML5 Navigator object
     * @private
     * @property navigator_
     */
    this.navigator_ = options.navigator;


    /**
     * If the user's position is being watched,
     * this is the ID of the returned by Navigator.geolocation.watchPosition.
     *
     * Is required to clear the watch.
     *
     * @type {number}
     * @property watchId_
     */
    this.watchId_ = null;
  };


  /**
   * @method getCurrentPosition
   */
  HTML5GeolocateService.prototype.getCurrentPosition = function() {
    var promise = new Promise();
    var callback = _.bind(function(res) {
      promise.resolve(this.createPosition_(res));
    }, this);
    var errback = _.bind(function(err) {
      promise.reject(this.createGeolocateError_(err));
    }, this);


    if (!HTML5GeolocateService.isSupported(this.navigator_)) {
      promise.reject(this.createServiceUnavailableError_());
    }
    else {
      this.navigator_.geolocation.getCurrentPosition(callback, errback, this.navigatorOptions_);
    }

    return promise;
  };


  /**
   * @method watchPosition
   */
  HTML5GeolocateService.prototype.watchPosition = function(onSuccess, onError, opt_options) {
    var self = this;

    if (!HTML5GeolocateService.isSupported(this.navigator_)) {
      onError(this.createServiceUnavailableError_());
    }
    else {
      this.watchId_ = this.navigator_.geolocation.watchPosition(
        function(res) {
          onSuccess(self.createPosition_(res));
        },
        function(error) {
          onError(self.createGeolocateError_(error));
        },
        this.navigatorOptions_
      );
    }
  };


  /**
   * @private
   * @return {aeris.geolocate.errors.GeolocateServiceError}
   * @method createServiceUnavailableError_
   */
  HTML5GeolocateService.prototype.createServiceUnavailableError_ = function() {
    return this.createGeolocateError_({
      message: 'HTML5 Geolocation is not available.',
      code: GeolocateServiceError.POSITION_UNAVAILABLE
    });
  };


  /**
   * @method clearWatch
   */
  HTML5GeolocateService.prototype.clearWatch = function() {
    if (_.isNull(this.watchId_)) { return; }

    this.navigator_.geolocation.clearWatch(this.watchId_);
    this.watchId_ = null;
  };


  /**
   * @method isSupported
   * @param {Navigator=} opt_navigator The navigator object
   *        for which to check geolocation support. Defaults
   *        to the global window.navigator object.
   */
  HTML5GeolocateService.isSupported = function(opt_navigator) {
    var navigator = arguments.length ? opt_navigator : root.navigator;

    return !!(navigator && navigator.geolocation);
  };


  /**
   * @param {Object} position Position data from the Geolocation API.
   * @return {aeris.geolocate.results.GeolocatePosition}
   * @private
   * @method createPosition_
   */
  HTML5GeolocateService.prototype.createPosition_ = function(position) {
    return new GeolocatePosition(_.extend(
      {
        latLon: [position.coords.latitude, position.coords.longitude],
        timestamp: position.timestamp || null
      },
      _.pick(position.coords,
        'altitude',
        'altitudeAccuracy',
        'accuracy',
        'heading',
        'speed'
      )
    ));
  };

  /**
   * @param {Object} error Error data from the Geolocation API.
   * @return {aeris.geolocate.errors.GeolocateServiceError}
   * @private
   * @method createGeolocateError_
   */
  HTML5GeolocateService.prototype.createGeolocateError_ = function(error) {
    return new GeolocateServiceError(error);
  };


  /**
   * @method setNavigator
   * @param {Navigator} navigator Set the navigator object to use for geolocation.
   */
  HTML5GeolocateService.prototype.setNavigator = function(navigator) {
    this.navigator_ = navigator;
  };



  return _.expose(HTML5GeolocateService, 'aeris.geolocate.HTML5GeolocateService');
});