modules/ui/geolocate.js (76 lines of code) (raw):
import { select as d3_select } from 'd3-selection';
import { t, localizer } from '../core/localizer';
import { uiTooltip } from './tooltip';
import { Extent } from '@id-sdk/extent';
import { modeBrowse } from '../modes/browse';
import { svgIcon } from '../svg/icon';
import { uiLoading } from './loading';
export function uiGeolocate(context) {
var _geolocationOptions = {
// prioritize speed and power usage over precision
enableHighAccuracy: false,
// don't hang indefinitely getting the location
timeout: 6000 // 6sec
};
var _locating = uiLoading(context).message(t.html('geolocate.locating')).blocking(true);
var _layer = context.layers().layer('geolocate');
var _position;
var _extent;
var _timeoutID;
var _button = d3_select(null);
function click() {
if (context.inIntro()) return;
if (!_layer.enabled() && !_locating.isShown()) {
// This timeout ensures that we still call finish() even if
// the user declines to share their location in Firefox
_timeoutID = setTimeout(error, 10000 /* 10sec */ );
context.container().call(_locating);
// get the latest position even if we already have one
navigator.geolocation.getCurrentPosition(success, error, _geolocationOptions);
} else {
_locating.close();
_layer.enabled(null, false);
updateButtonState();
}
}
function zoomTo() {
context.enter(modeBrowse(context));
var map = context.map();
_layer.enabled(_position, true);
updateButtonState();
map.centerZoomEase(_extent.center(), Math.min(20, map.extentZoom(_extent)));
}
function success(geolocation) {
_position = geolocation;
var coords = _position.coords;
_extent = new Extent([coords.longitude, coords.latitude]).padByMeters(coords.accuracy);
zoomTo();
finish();
}
function error() {
if (_position) {
// use the position from a previous call if we have one
zoomTo();
} else {
context.ui().flash
.label(t.html('geolocate.location_unavailable'))
.iconName('#iD-icon-geolocate')();
}
finish();
}
function finish() {
_locating.close(); // unblock ui
if (_timeoutID) { clearTimeout(_timeoutID); }
_timeoutID = undefined;
}
function updateButtonState() {
_button.classed('active', _layer.enabled());
}
return function(selection) {
if (!navigator.geolocation || !navigator.geolocation.getCurrentPosition) return;
_button = selection
.append('button')
.on('click', click)
.call(svgIcon('#iD-icon-geolocate', 'light'))
.call(uiTooltip()
.placement((localizer.textDirection() === 'rtl') ? 'right' : 'left')
.title(t.html('geolocate.title'))
.keys([t('geolocate.key')])
);
context.keybinding().on(t('geolocate.key'), click);
};
}