diff --git a/api/web/src/components/CloudTAK/Map.vue b/api/web/src/components/CloudTAK/Map.vue index 1ae270bca..96779d2c5 100644 --- a/api/web/src/components/CloudTAK/Map.vue +++ b/api/web/src/components/CloudTAK/Map.vue @@ -48,14 +48,22 @@ class='position-absolute bottom-0 begin-0 text-white' style=' z-index: 1; - width: 200px; + width: 250px; height: 40px; border-radius: 0px 6px 0px 0px; background-color: rgba(0, 0, 0, 0.5); ' > -
+
+
import WarnChannels from './util/WarnChannels.vue'; +import Status from '../util/Status.vue'; import CoordInput from './CoordInput.vue'; import { std, stdurl } from '/src/std.ts'; import CloudTAKFeatView from './FeatView.vue'; @@ -678,6 +687,7 @@ export default { feat: null, // Show the Feat Viewer sidebar locked: [], // Lock the map view to a given CoT - The last element is the currently locked value // this is an array so that things like the radial menu can temporarily lock state but remember the previous lock value when they are closed + live_loc_denied: false, // User denied live location services live_loc: false, upload: { shown: false, @@ -685,7 +695,6 @@ export default { }, timer: null, // Interval for pushing GeoJSON Map Updates (CoT) timerSelf: null, // Interval for pushing your location to the server - timerSelfUpdate: null, // Interval for updating actual GPS location loading: { // Any Loading related states main: true @@ -696,7 +705,6 @@ export default { beforeUnmount: function() { if (this.timer) window.clearInterval(this.timer); if (this.timerSelf) window.clearInterval(this.timerSelf); - if (this.timerSelfUpdate) window.clearInterval(this.timerSelfUpdate); if (connectionStore.ws) connectionStore.ws.close(); if (mapStore.map) { @@ -799,43 +807,54 @@ export default { return mapStore.map.getZoom(); }, getLocation: function(flyTo = false) { + if (this.live_loc_denied && flyTo) throw new Error('Cannot navigate to your position as you denied location services'); + else if (this.live_loc_denied) return; + if (flyTo && !("geolocation" in navigator)) { throw new Error('GeoLocation is not available in this browser'); } else if (!("geolocation" in navigator)) { + console.error('geolocation object not found on navigator'); return; } - navigator.geolocation.getCurrentPosition( - (position) => { - if (flyTo) { - mapStore.map.flyTo({ - center: [position.coords.longitude, position.coords.latitude], - zoom: 14 - }); - } else if (position.coords.accuracy <= 500) { - this.live_loc = { - type: 'Feature', - properties: { - accuracy: position.coords.accuracy - }, - geometry: { - type: 'Point', - coordinates: [ - position.coords.longitude, - position.coords.latitude - ], - } + navigator.geolocation.getCurrentPosition((position) => { + if (flyTo) { + mapStore.map.flyTo({ + center: [position.coords.longitude, position.coords.latitude], + zoom: 14 + }); + } else if (position.coords.accuracy <= 500) { + this.live_loc = { + type: 'Feature', + properties: { + accuracy: position.coords.accuracy + }, + geometry: { + type: 'Point', + coordinates: [ + position.coords.longitude, + position.coords.latitude + ], } - - this.setYou(this.live_loc); } - }, (err) => { - console.error(err); - },{ - maximumAge: 300000, - enableHighAccuracy: true + + this.setYou(this.live_loc); } - ); + }, (err) => { + if (err.message === 'User denied geolocation prompt') { + this.live_loc_denied = true; + } else if ( + err.message !== 'Position unavailable' + && err.message !== 'Position acquisition timed out' + && err.message !== 'Timeout expired' + ) { + this.$emit('err', err); + } + },{ + maximumAge: 0, + timeout: 1500, + enableHighAccuracy: true + }); }, startDraw: function(type) { mapStore.draw.start(); @@ -1021,6 +1040,8 @@ export default { }); this.timerSelf = window.setInterval(() => { + this.getLocation(false); + if (this.live_loc) { connectionStore.sendCOT(profileStore.CoT(this.live_loc)) } else if (profileStore.profile.tak_loc) { @@ -1028,10 +1049,6 @@ export default { } }, 2000); - this.timerSelfUpdate = window.setInterval(() => { - this.getLocation(false); - }, 5000); - this.timer = window.setInterval(async () => { if (!mapStore.map) return; await this.updateCOT(); @@ -1043,6 +1060,7 @@ export default { } }, components: { + Status, CoordInput, WarnChannels, SideMenu, diff --git a/api/web/src/components/CloudTAK/util/Coordinate.vue b/api/web/src/components/CloudTAK/util/Coordinate.vue index 5dfe08cf1..4d41d19e0 100644 --- a/api/web/src/components/CloudTAK/util/Coordinate.vue +++ b/api/web/src/components/CloudTAK/util/Coordinate.vue @@ -1,6 +1,6 @@ - DD - DMS - MGRS - UTM +
@@ -70,10 +72,18 @@ export default { CopyField, }, props: { + label: { + type: String, + default: 'Coordinates' + }, edit: { type: Boolean, default: false }, + truncate: { + type: Number, + description: 'Truncate DD coordinates to a given precision' + }, modes: { type: Array, default: function() { @@ -98,7 +108,16 @@ export default { }, computed: { inMode: function() { - if (this.mode === 'dd') return `${this.modelValue[1]}, ${this.modelValue[0]}`; + if (this.mode === 'dd') { + if (this.truncate) { + return [ + Math.trunc(this.modelValue[1] * Math.pow(10, this.truncate)) / Math.pow(10, this.truncate), + Math.trunc(this.modelValue[0] * Math.pow(10, this.truncate)) / Math.pow(10, this.truncate) + ].join(', '); + } else { + return `${this.modelValue[1]}, ${this.modelValue[0]}`; + } + } else if (this.mode === 'dms') return `${this.asDMS(this.modelValue[1])}, ${this.asDMS(this.modelValue[0])}`; else if (this.mode === 'mgrs') return this.asMGRS(); else if (this.mode === 'utm') return this.asUTM(this.modelValue[1], this.modelValue[0]); diff --git a/api/web/src/components/CloudTAK/util/CopyField.vue b/api/web/src/components/CloudTAK/util/CopyField.vue index 5bd54739e..e234cabf7 100644 --- a/api/web/src/components/CloudTAK/util/CopyField.vue +++ b/api/web/src/components/CloudTAK/util/CopyField.vue @@ -1,6 +1,6 @@