/* Copyright (c) 2019 Jean-Marc VIGLINO, released under the CeCILL-B license (French BSD license) (http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt). */ import {transform as ol_proj_transform} from 'ol/proj.js' import {toStringHDMS as ol_coordinate_toStringHDMS} from 'ol/coordinate.js'; import ol_Geolocation from 'ol/Geolocation.js' import ol_control_Search from './Search.js' import ol_ext_element from '../util/element.js' /** * Search on GPS coordinate. * * @constructor * @extends {ol_control_Search} * @fires select * @param {Object=} Control options. * @param {string} [options.className] control class name * @param {Element | string | undefined} [options.target] Specify a target if you want the control to be rendered outside of the map's viewport. * @param {string | undefined} [options.label=search] Text label to use for the search button, default "search" * @param {string | undefined} [options.labelGPS="Locate with GPS"] placeholder, default "Locate with GPS" * @param {number | undefined} [options.typing=300] a delay on each typing to start searching (ms), default 300. * @param {integer | undefined} [options.minLength=1] minimum length to start searching, default 1 * @param {integer | undefined} [options.maxItems=10] maximum number of items to display in the autocomplete list, default 10 */ var ol_control_SearchGPS = class olcontrolSearchGPS extends ol_control_Search { constructor(options) { options = options || {}; options.className = (options.className || '') + ' ol-searchgps'; options.placeholder = options.placeholder || 'lon,lat'; super(options); // Geolocation this.geolocation = new ol_Geolocation({ projection: "EPSG:4326", trackingOptions: { maximumAge: 10000, enableHighAccuracy: true, timeout: 600000 } }); ol_ext_element.create('BUTTON', { className: 'ol-geoloc', title: options.labelGPS || 'Locate with GPS', parent: this.element, click: function () { this.geolocation.setTracking(true); }.bind(this) }); // DMS switcher ol_ext_element.createSwitch({ html: 'decimal', after: 'DMS', change: function (e) { if (e.target.checked) { this.element.classList.add('ol-dms'); } else { this.element.classList.remove('ol-dms'); } }.bind(this), parent: this.element }); this._createForm(); // Move list to the end var ul = this.element.querySelector("ul.autocomplete"); this.element.appendChild(ul); } /** Set the input value in the form (for initialisation purpose) * @param {Array} [coord] if none get the map center * @api */ setInput(coord) { if (!coord) { if (!this.getMap()) return coord = this.getMap().getView().getCenter(); coord = ol_proj_transform(coord, this.getMap().getView().getProjection(), 'EPSG:4326') } this.inputs_[0].value = coord[0]; this.inputs_[1].value = coord[1]; this._triggerCustomEvent('keyup', this.inputs_[0]); } /** Create input form * @private */ _createForm() { // Value has change var onchange = function (e) { if (e.target.classList.contains('ol-dms')) { lon.value = (lond.value < 0 ? -1 : 1) * Number(lond.value) + Number(lonm.value) / 60 + Number(lons.value) / 3600; lon.value = (lond.value < 0 ? -1 : 1) * Math.round(lon.value * 10000000) / 10000000; lat.value = (latd.value < 0 ? -1 : 1) * Number(latd.value) + Number(latm.value) / 60 + Number(lats.value) / 3600; lat.value = (latd.value < 0 ? -1 : 1) * Math.round(lat.value * 10000000) / 10000000; } if (lon.value || lat.value) { this._input.value = lon.value + ',' + lat.value; } else { this._input.value = ''; } if (!e.target.classList.contains('ol-dms')) { var s = ol_coordinate_toStringHDMS([Number(lon.value) || 0, Number(lat.value) || 0]); var c = s.replace(/(N|S)/g,'-').replace(/(E|W)/g, '').split('-'); try { c[1] = c[1].trim().split(' '); lond.value = (/W/.test(s) ? -1 : 1) * parseInt(c[1][0]); lonm.value = parseInt(c[1][1] || 0); lons.value = parseInt(c[1][2] || 0); c[0] = c[0].trim().split(' '); latd.value = (/S/.test(s) ? -1 : 1) * parseInt(c[0][0]); latm.value = parseInt(c[0][1] || 0); lats.value = parseInt(c[0][2] || 0); } catch(e) { /* oops */ } } this.search(); }.bind(this); function createInput(className, unit) { var input = ol_ext_element.create('INPUT', { className: className, type: 'number', step: 'any', lang: 'en', parent: div, on: { 'change keyup': onchange } }); if (unit) { ol_ext_element.create('SPAN', { className: 'ol-dms', html: unit, parent: div, }); } return input; } // Longitude var div = ol_ext_element.create('DIV', { className: 'ol-longitude', parent: this.element }); ol_ext_element.create('LABEL', { html: 'Longitude', parent: div }); var lon = createInput('ol-decimal'); var lond = createInput('ol-dms', '°'); var lonm = createInput('ol-dms', '\''); var lons = createInput('ol-dms', '"'); // Latitude div = ol_ext_element.create('DIV', { className: 'ol-latitude', parent: this.element }); ol_ext_element.create('LABEL', { html: 'Latitude', parent: div }); var lat = createInput('ol-decimal'); var latd = createInput('ol-dms', '°'); var latm = createInput('ol-dms', '\''); var lats = createInput('ol-dms', '"'); this.inputs_ = [lon, lat] // Focus on open if (this.button) { this.button.addEventListener("click", function () { lon.focus(); }); } // Change value on click this.on('select', function (e) { lon.value = e.search.gps[0]; lat.value = e.search.gps[1]; }.bind(this)); // Change value on geolocation this.geolocation.on('change', function () { this.geolocation.setTracking(false); var coord = this.geolocation.getPosition(); lon.value = coord[0]; lat.value = coord[1]; this._triggerCustomEvent('keyup', lon); }.bind(this)); } /** Autocomplete function * @param {string} s search string * @return {Array|false} an array of search solutions * @api */ autocomplete(s) { var result = []; var c = s.split(','); c[0] = Number(c[0]); c[1] = Number(c[1]); // Name s = ol_coordinate_toStringHDMS(c); if (s) s = s.replace(/(°|′|″) /g, '$1'); // var coord = ol_proj_transform([c[0], c[1]], 'EPSG:4326', this.getMap().getView().getProjection()); result.push({ gps: c, coordinate: coord, name: s }); return result; } } export default ol_control_SearchGPS