fix track mock location
This commit is contained in:
parent
7fdece0a28
commit
88352279a9
2 changed files with 206 additions and 158 deletions
|
|
@ -32,7 +32,7 @@ const apiKey = ref<string>(
|
||||||
)
|
)
|
||||||
const zoomMap = ref<number>(18)
|
const zoomMap = ref<number>(18)
|
||||||
|
|
||||||
async function initializeMap() {
|
async function initializeMap(position: GeolocationPosition) {
|
||||||
try {
|
try {
|
||||||
// Load modules of ArcGIS
|
// Load modules of ArcGIS
|
||||||
loadModules([
|
loadModules([
|
||||||
|
|
@ -43,159 +43,146 @@ async function initializeMap() {
|
||||||
'esri/Graphic',
|
'esri/Graphic',
|
||||||
'esri/layers/TileLayer',
|
'esri/layers/TileLayer',
|
||||||
]).then(async ([esriConfig, Map, MapView, Point, Graphic, TileLayer]) => {
|
]).then(async ([esriConfig, Map, MapView, Point, Graphic, TileLayer]) => {
|
||||||
// Set apiKey
|
|
||||||
// esriConfig.apiKey =
|
|
||||||
// 'AAPK4f700a4324d04e9f8a1a134e0771ac45FXWawdCl-OotFfr52gz9XKxTDJTpDzw_YYcwbmKDDyAJswf14FoPyw0qBkN64DvP'
|
|
||||||
|
|
||||||
// Create a FeatureLayer using a custom server URL
|
|
||||||
// const hillshadeLayer = new TileLayer({
|
|
||||||
// url: `https://bmagis.bangkok.go.th/arcgis/rest/services/cache/BMA_3D_2D_Cache/MapServer`,
|
|
||||||
// })
|
|
||||||
|
|
||||||
const map = new Map({
|
const map = new Map({
|
||||||
basemap: 'streets',
|
basemap: 'streets',
|
||||||
// basemap: 'arcgis-topographic',
|
|
||||||
// layers: [hillshadeLayer],
|
|
||||||
})
|
})
|
||||||
|
|
||||||
navigator.geolocation.getCurrentPosition(async (position) => {
|
const { latitude, longitude } = position.coords
|
||||||
const { latitude, longitude } = position.coords
|
|
||||||
|
|
||||||
const mapView = new MapView({
|
const mapView = new MapView({
|
||||||
container: 'mapViewDisplay',
|
container: 'mapViewDisplay',
|
||||||
map: map,
|
map: map,
|
||||||
center: {
|
center: {
|
||||||
latitude: latitude,
|
latitude: latitude,
|
||||||
longitude: longitude,
|
longitude: longitude,
|
||||||
}, // Set the initial map center current position
|
}, // Set the initial map center current position
|
||||||
|
|
||||||
zoom: zoomMap.value,
|
zoom: zoomMap.value,
|
||||||
constraints: {
|
constraints: {
|
||||||
snapToZoom: false, // Disables snapping to the zoom level
|
snapToZoom: false, // Disables snapping to the zoom level
|
||||||
minZoom: zoomMap.value, // Set minimum zoom level
|
minZoom: zoomMap.value, // Set minimum zoom level
|
||||||
maxZoom: zoomMap.value, // Set maximum zoom level (same as minZoom for fixed zoom)
|
maxZoom: zoomMap.value, // Set maximum zoom level (same as minZoom for fixed zoom)
|
||||||
},
|
},
|
||||||
|
|
||||||
ui: {
|
ui: {
|
||||||
components: [], // Empty array to remove all default UI components
|
components: [], // Empty array to remove all default UI components
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
// ตำแหน่งของผู้ใช้
|
// ตำแหน่งของผู้ใช้
|
||||||
const userPoint = new Point({ longitude, latitude })
|
const userPoint = new Point({ longitude, latitude })
|
||||||
const userSymbol = {
|
const userSymbol = {
|
||||||
type: 'picture-marker',
|
type: 'picture-marker',
|
||||||
url: 'http://maps.google.com/mapfiles/ms/icons/red.png',
|
url: 'http://maps.google.com/mapfiles/ms/icons/red.png',
|
||||||
width: '32px',
|
width: '32px',
|
||||||
height: '32px',
|
height: '32px',
|
||||||
}
|
}
|
||||||
const userGraphic = new Graphic({
|
const userGraphic = new Graphic({
|
||||||
geometry: userPoint,
|
geometry: userPoint,
|
||||||
symbol: userSymbol,
|
symbol: userSymbol,
|
||||||
})
|
})
|
||||||
mapView.graphics.add(userGraphic)
|
mapView.graphics.add(userGraphic)
|
||||||
// Get POI place ยิงไปขอที่ server ของกทม.ก่อน
|
// Get POI place ยิงไปขอที่ server ของกทม.ก่อน
|
||||||
await axios
|
await axios
|
||||||
.get(
|
.get(
|
||||||
'https://bmagis.bangkok.go.th/portal/sharing/servers/e4732c3a9fe549ab8bc697573b468f68/rest/services/World/GeocodeServer/reverseGeocode/',
|
'https://bmagis.bangkok.go.th/portal/sharing/servers/e4732c3a9fe549ab8bc697573b468f68/rest/services/World/GeocodeServer/reverseGeocode/',
|
||||||
{
|
{
|
||||||
params: {
|
params: {
|
||||||
f: 'json', // Format JSON response
|
f: 'json', // Format JSON response
|
||||||
distance: 2000,
|
distance: 2000,
|
||||||
category: 'POI',
|
category: 'POI',
|
||||||
location: {
|
location: {
|
||||||
spatialReference: { wkid: 4326 },
|
spatialReference: { wkid: 4326 },
|
||||||
x: longitude,
|
x: longitude,
|
||||||
y: latitude,
|
y: latitude,
|
||||||
},
|
|
||||||
token: apiKey.value,
|
|
||||||
},
|
},
|
||||||
}
|
token: apiKey.value,
|
||||||
)
|
},
|
||||||
.then((response) => {
|
}
|
||||||
// console.log('poi', response.data.location)
|
)
|
||||||
poiPlaceName.value = response.data.address
|
.then((response) => {
|
||||||
? response.data.address.PlaceName === ''
|
// console.log('poi', response.data.location)
|
||||||
? response.data.address.ShortLabel
|
poiPlaceName.value = response.data.address
|
||||||
: response.data.address.PlaceName
|
? response.data.address.PlaceName === ''
|
||||||
: 'ไม่พบข้อมูล'
|
? response.data.address.ShortLabel
|
||||||
const poiPoint = new Point({
|
: response.data.address.PlaceName
|
||||||
longitude: response.data.location.x,
|
: 'ไม่พบข้อมูล'
|
||||||
latitude: response.data.location.y,
|
const poiPoint = new Point({
|
||||||
})
|
longitude: response.data.location.x,
|
||||||
const poiSymbol = {
|
latitude: response.data.location.y,
|
||||||
type: 'picture-marker',
|
|
||||||
url: 'http://maps.google.com/mapfiles/ms/icons/blue.png',
|
|
||||||
width: '32px',
|
|
||||||
height: '32px',
|
|
||||||
}
|
|
||||||
const poiGraphic = new Graphic({
|
|
||||||
geometry: poiPoint,
|
|
||||||
symbol: poiSymbol,
|
|
||||||
})
|
|
||||||
mapView.graphics.add(poiGraphic)
|
|
||||||
// อัปเดตการแสดงผลให้แสดงทั้งตำแหน่งของผู้ใช้และ POI
|
|
||||||
mapView.goTo({
|
|
||||||
target: [userPoint, poiPoint],
|
|
||||||
zoom: zoomMap.value,
|
|
||||||
})
|
|
||||||
|
|
||||||
updateLocation(latitude, longitude, poiPlaceName.value)
|
|
||||||
})
|
})
|
||||||
.catch(async (error) => {
|
const poiSymbol = {
|
||||||
// console.error('Error fetching points of interest:', error)
|
type: 'picture-marker',
|
||||||
// Get POI place ยิงไปขอที่ server arcgis ไม่ต้องใช้ token
|
url: 'http://maps.google.com/mapfiles/ms/icons/blue.png',
|
||||||
await axios
|
width: '32px',
|
||||||
.get(
|
height: '32px',
|
||||||
'https://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/reverseGeocode/',
|
}
|
||||||
{
|
const poiGraphic = new Graphic({
|
||||||
params: {
|
geometry: poiPoint,
|
||||||
f: 'json', // Format JSON response
|
symbol: poiSymbol,
|
||||||
distance: 2000,
|
})
|
||||||
category: 'POI',
|
mapView.graphics.add(poiGraphic)
|
||||||
location: {
|
// อัปเดตการแสดงผลให้แสดงทั้งตำแหน่งของผู้ใช้และ POI
|
||||||
spatialReference: { wkid: 4326 },
|
mapView.goTo({
|
||||||
x: longitude,
|
target: [userPoint, poiPoint],
|
||||||
y: latitude,
|
zoom: zoomMap.value,
|
||||||
},
|
})
|
||||||
|
|
||||||
|
updateLocation(latitude, longitude, poiPlaceName.value)
|
||||||
|
})
|
||||||
|
.catch(async (error) => {
|
||||||
|
// console.error('Error fetching points of interest:', error)
|
||||||
|
// Get POI place ยิงไปขอที่ server arcgis ไม่ต้องใช้ token
|
||||||
|
await axios
|
||||||
|
.get(
|
||||||
|
'https://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/reverseGeocode/',
|
||||||
|
{
|
||||||
|
params: {
|
||||||
|
f: 'json', // Format JSON response
|
||||||
|
distance: 2000,
|
||||||
|
category: 'POI',
|
||||||
|
location: {
|
||||||
|
spatialReference: { wkid: 4326 },
|
||||||
|
x: longitude,
|
||||||
|
y: latitude,
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
)
|
}
|
||||||
.then((response) => {
|
)
|
||||||
// console.log('poi', response.data.location)
|
.then((response) => {
|
||||||
poiPlaceName.value = response.data.address
|
// console.log('poi', response.data.location)
|
||||||
? response.data.address.PlaceName === ''
|
poiPlaceName.value = response.data.address
|
||||||
? response.data.address.ShortLabel
|
? response.data.address.PlaceName === ''
|
||||||
: response.data.address.PlaceName
|
? response.data.address.ShortLabel
|
||||||
: 'ไม่พบข้อมูล'
|
: response.data.address.PlaceName
|
||||||
const poiPoint = new Point({
|
: 'ไม่พบข้อมูล'
|
||||||
longitude: response.data.location.x,
|
const poiPoint = new Point({
|
||||||
latitude: response.data.location.y,
|
longitude: response.data.location.x,
|
||||||
})
|
latitude: response.data.location.y,
|
||||||
const poiSymbol = {
|
})
|
||||||
type: 'picture-marker',
|
const poiSymbol = {
|
||||||
url: 'http://maps.google.com/mapfiles/ms/icons/blue.png',
|
type: 'picture-marker',
|
||||||
width: '32px',
|
url: 'http://maps.google.com/mapfiles/ms/icons/blue.png',
|
||||||
height: '32px',
|
width: '32px',
|
||||||
}
|
height: '32px',
|
||||||
const poiGraphic = new Graphic({
|
}
|
||||||
geometry: poiPoint,
|
const poiGraphic = new Graphic({
|
||||||
symbol: poiSymbol,
|
geometry: poiPoint,
|
||||||
})
|
symbol: poiSymbol,
|
||||||
mapView.graphics.add(poiGraphic)
|
})
|
||||||
// อัปเดตการแสดงผลให้แสดงทั้งตำแหน่งของผู้ใช้และ POI
|
mapView.graphics.add(poiGraphic)
|
||||||
mapView.goTo({
|
// อัปเดตการแสดงผลให้แสดงทั้งตำแหน่งของผู้ใช้และ POI
|
||||||
target: [userPoint, poiPoint],
|
mapView.goTo({
|
||||||
zoom: zoomMap.value,
|
target: [userPoint, poiPoint],
|
||||||
})
|
zoom: zoomMap.value,
|
||||||
|
})
|
||||||
|
|
||||||
updateLocation(latitude, longitude, poiPlaceName.value)
|
updateLocation(latitude, longitude, poiPlaceName.value)
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
// console.error('Error fetching points of interest:', error)
|
// console.error('Error fetching points of interest:', error)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
|
||||||
})
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error loading the map', error)
|
console.error('Error loading the map', error)
|
||||||
|
|
@ -236,7 +223,7 @@ const requestLocationPermission = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for critical errors (invalid coordinates) that prevent showing location
|
// Check for critical errors (invalid coordinates) that prevent showing location
|
||||||
const hasCriticalErrors = validationResult.errors.some(error =>
|
const hasCriticalErrors = validationResult.errors.some((error) =>
|
||||||
error.includes('พิกัดตำแหน่งไม่ถูกต้อง')
|
error.includes('พิกัดตำแหน่งไม่ถูกต้อง')
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -261,7 +248,7 @@ const requestLocationPermission = () => {
|
||||||
|
|
||||||
// Center map on user's location if map is initialized
|
// Center map on user's location if map is initialized
|
||||||
if (privacyStore.isAccepted) {
|
if (privacyStore.isAccepted) {
|
||||||
await initializeMap()
|
await initializeMap(position)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ export const VALIDATION_CONFIG = {
|
||||||
MAX_SPEED_MS: 100, // 100 m/s (~360 km/h) - maximum plausible movement speed
|
MAX_SPEED_MS: 100, // 100 m/s (~360 km/h) - maximum plausible movement speed
|
||||||
POSITION_HISTORY_SIZE: 5, // number of positions to keep for pattern detection
|
POSITION_HISTORY_SIZE: 5, // number of positions to keep for pattern detection
|
||||||
MOCK_INDICATOR_THRESHOLD: 3, // threshold for mock detection (indicators >= 3 = mock)
|
MOCK_INDICATOR_THRESHOLD: 3, // threshold for mock detection (indicators >= 3 = mock)
|
||||||
|
SUSPICIOUS_ACCURACY_MAX: 5, // accuracy ≤ 5m AND integer = suspicious (real GPS never rounds to whole number)
|
||||||
} as const
|
} as const
|
||||||
|
|
||||||
export function useLocationValidation() {
|
export function useLocationValidation() {
|
||||||
|
|
@ -31,17 +32,26 @@ export function useLocationValidation() {
|
||||||
|
|
||||||
// Thai error messages - exported for i18n consistency
|
// Thai error messages - exported for i18n consistency
|
||||||
const errorMessages = {
|
const errorMessages = {
|
||||||
MOCK_DETECTED: 'ตรวจพบว่าตำแหน่ง GPS อาจไม่ถูกต้อง กรุณาปิดแอปจำลองตำแหน่งและลองใหม่',
|
MOCK_DETECTED:
|
||||||
|
'ตรวจพบว่าตำแหน่ง GPS อาจไม่ถูกต้อง กรุณาปิดแอปจำลองตำแหน่งและลองใหม่',
|
||||||
INVALID_COORDINATES: 'พิกัดตำแหน่งไม่ถูกต้อง กรุณาลองใหม่',
|
INVALID_COORDINATES: 'พิกัดตำแหน่งไม่ถูกต้อง กรุณาลองใหม่',
|
||||||
STALE_TIMESTAMP: 'ข้อมูลตำแหน่งเก่าเกินไป กรุณารับสัญญาณ GPS ใหม่',
|
STALE_TIMESTAMP: 'ข้อมูลตำแหน่งเก่าเกินไป กรุณารับสัญญาณ GPS ใหม่',
|
||||||
POOR_ACCURACY: 'ความแม่นยำตำแหน่งต่ำเกินไป กรุณาตรวจสอบการรับสัญญาณ GPS',
|
POOR_ACCURACY: 'ความแม่นยำตำแหน่งต่ำเกินไป กรุณาตรวจสอบการรับสัญญาณ GPS',
|
||||||
IMPOSSIBLE_SPEED: 'ตรวจพบการเคลื่อนที่ด้วยความเร็วผิดปกติ อาจเป็นการจำลองตำแหน่ง',
|
IMPOSSIBLE_SPEED:
|
||||||
|
'ตรวจพบการเคลื่อนที่ด้วยความเร็วผิดปกติ อาจเป็นการจำลองตำแหน่ง',
|
||||||
|
SUSPICIOUS_ACCURACY: 'ตรวจพบค่าความแม่นยำที่ผิดปกติ อาจเป็นการจำลองตำแหน่ง',
|
||||||
|
DUPLICATE_POSITION: 'ตรวจพบพิกัดตำแหน่งซ้ำกัน อาจเป็นการจำลองตำแหน่ง',
|
||||||
}
|
}
|
||||||
|
|
||||||
const previousPositions = ref<PositionSnapshot[]>([])
|
const previousPositions = ref<PositionSnapshot[]>([])
|
||||||
|
|
||||||
// คำนวณระยะห่างระหว่าง 2 จุด (Haversine formula)
|
// คำนวณระยะห่างระหว่าง 2 จุด (Haversine formula)
|
||||||
const haversineDistance = (lat1: number, lon1: number, lat2: number, lon2: number): number => {
|
const haversineDistance = (
|
||||||
|
lat1: number,
|
||||||
|
lon1: number,
|
||||||
|
lat2: number,
|
||||||
|
lon2: number
|
||||||
|
): number => {
|
||||||
const R = 6371e3 // Earth's radius in meters
|
const R = 6371e3 // Earth's radius in meters
|
||||||
const φ1 = (lat1 * Math.PI) / 180
|
const φ1 = (lat1 * Math.PI) / 180
|
||||||
const φ2 = (lat2 * Math.PI) / 180
|
const φ2 = (lat2 * Math.PI) / 180
|
||||||
|
|
@ -59,9 +69,12 @@ export function useLocationValidation() {
|
||||||
// ตรวจสอบพิกัดถูกต้อง
|
// ตรวจสอบพิกัดถูกต้อง
|
||||||
const validateCoordinates = (lat: number, lon: number): boolean => {
|
const validateCoordinates = (lat: number, lon: number): boolean => {
|
||||||
return (
|
return (
|
||||||
lat >= -90 && lat <= 90 &&
|
lat >= -90 &&
|
||||||
lon >= -180 && lon <= 180 &&
|
lat <= 90 &&
|
||||||
!isNaN(lat) && !isNaN(lon) &&
|
lon >= -180 &&
|
||||||
|
lon <= 180 &&
|
||||||
|
!isNaN(lat) &&
|
||||||
|
!isNaN(lon) &&
|
||||||
!(lat === 0 && lon === 0) // Mock มักใช้ 0,0
|
!(lat === 0 && lon === 0) // Mock มักใช้ 0,0
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -80,20 +93,49 @@ export function useLocationValidation() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// คำนวณความเร็ว
|
// คำนวณความเร็ว
|
||||||
const calculateSpeed = (pos1: PositionSnapshot, pos2: PositionSnapshot): number => {
|
const calculateSpeed = (
|
||||||
const distance = haversineDistance(pos1.latitude, pos1.longitude, pos2.latitude, pos2.longitude)
|
pos1: PositionSnapshot,
|
||||||
|
pos2: PositionSnapshot
|
||||||
|
): number => {
|
||||||
|
const distance = haversineDistance(
|
||||||
|
pos1.latitude,
|
||||||
|
pos1.longitude,
|
||||||
|
pos2.latitude,
|
||||||
|
pos2.longitude
|
||||||
|
)
|
||||||
const timeDiff = Math.abs(pos2.timestamp - pos1.timestamp) / 1000 // seconds
|
const timeDiff = Math.abs(pos2.timestamp - pos1.timestamp) / 1000 // seconds
|
||||||
return timeDiff > 0 ? distance / timeDiff : 0
|
return timeDiff > 0 ? distance / timeDiff : 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// ตรวจสอบความเร็วปกติ
|
// ตรวจสอบความเร็วปกติ
|
||||||
const validateSpeed = (current: PositionSnapshot, previous: PositionSnapshot): boolean => {
|
const validateSpeed = (
|
||||||
|
current: PositionSnapshot,
|
||||||
|
previous: PositionSnapshot
|
||||||
|
): boolean => {
|
||||||
const speed = calculateSpeed(previous, current)
|
const speed = calculateSpeed(previous, current)
|
||||||
return speed <= VALIDATION_CONFIG.MAX_SPEED_MS
|
return speed <= VALIDATION_CONFIG.MAX_SPEED_MS
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ตรวจสอบค่าความแม่นยำที่ผิดปกติ (mock apps มักรายงานค่าที่เป็นเลขจำนวนเต็มสวยงาม เช่น 5.0, 3.0)
|
||||||
|
const hasSuspiciousPerfectAccuracy = (accuracy: number | null): boolean => {
|
||||||
|
if (accuracy === null) return false
|
||||||
|
return (
|
||||||
|
Number.isInteger(accuracy) &&
|
||||||
|
accuracy <= VALIDATION_CONFIG.SUSPICIOUS_ACCURACY_MAX
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ตรวจสอบพิกัดซ้ำกันทุกค่า (real GPS มีการสั่นเล็กน้อย mock app มักคืนพิกัดเดิมซ้ำ)
|
||||||
|
const hasDuplicateCoordinates = (lat: number, lon: number): boolean => {
|
||||||
|
return previousPositions.value.some(
|
||||||
|
(p) => p.latitude === lat && p.longitude === lon
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// Main validation function
|
// Main validation function
|
||||||
const validateLocation = (position: GeolocationPosition): LocationValidationResult => {
|
const validateLocation = (
|
||||||
|
position: GeolocationPosition
|
||||||
|
): LocationValidationResult => {
|
||||||
const warnings: string[] = []
|
const warnings: string[] = []
|
||||||
const errors: string[] = []
|
const errors: string[] = []
|
||||||
let mockIndicators = 0
|
let mockIndicators = 0
|
||||||
|
|
@ -121,7 +163,8 @@ export function useLocationValidation() {
|
||||||
|
|
||||||
// 4. Compare with previous positions
|
// 4. Compare with previous positions
|
||||||
if (previousPositions.value.length > 0) {
|
if (previousPositions.value.length > 0) {
|
||||||
const previous = previousPositions.value[previousPositions.value.length - 1]
|
const previous =
|
||||||
|
previousPositions.value[previousPositions.value.length - 1]
|
||||||
|
|
||||||
if (!validateSpeed({ latitude, longitude, timestamp }, previous)) {
|
if (!validateSpeed({ latitude, longitude, timestamp }, previous)) {
|
||||||
errors.push(errorMessages.IMPOSSIBLE_SPEED)
|
errors.push(errorMessages.IMPOSSIBLE_SPEED)
|
||||||
|
|
@ -129,14 +172,32 @@ export function useLocationValidation() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 5. Suspiciously perfect accuracy — real GPS never rounds to a whole-number ≤ 5m
|
||||||
|
if (hasSuspiciousPerfectAccuracy(accuracy)) {
|
||||||
|
warnings.push(errorMessages.SUSPICIOUS_ACCURACY)
|
||||||
|
mockIndicators += 2
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6. Exact duplicate coordinates — real GPS always drifts slightly between readings
|
||||||
|
if (
|
||||||
|
previousPositions.value.length > 0 &&
|
||||||
|
hasDuplicateCoordinates(latitude, longitude)
|
||||||
|
) {
|
||||||
|
warnings.push(errorMessages.DUPLICATE_POSITION)
|
||||||
|
mockIndicators += 2
|
||||||
|
}
|
||||||
|
|
||||||
// Store current position
|
// Store current position
|
||||||
previousPositions.value.push({ latitude, longitude, timestamp })
|
previousPositions.value.push({ latitude, longitude, timestamp })
|
||||||
if (previousPositions.value.length > VALIDATION_CONFIG.POSITION_HISTORY_SIZE) {
|
if (
|
||||||
|
previousPositions.value.length > VALIDATION_CONFIG.POSITION_HISTORY_SIZE
|
||||||
|
) {
|
||||||
previousPositions.value.shift()
|
previousPositions.value.shift()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine result
|
// Determine result
|
||||||
const isMockDetected = mockIndicators >= VALIDATION_CONFIG.MOCK_INDICATOR_THRESHOLD
|
const isMockDetected =
|
||||||
|
mockIndicators >= VALIDATION_CONFIG.MOCK_INDICATOR_THRESHOLD
|
||||||
const isValid = errors.length === 0
|
const isValid = errors.length === 0
|
||||||
|
|
||||||
let confidence: 'low' | 'medium' | 'high' = 'low'
|
let confidence: 'low' | 'medium' | 'high' = 'low'
|
||||||
|
|
@ -154,7 +215,7 @@ export function useLocationValidation() {
|
||||||
|
|
||||||
const showMockWarning = (result: LocationValidationResult) => {
|
const showMockWarning = (result: LocationValidationResult) => {
|
||||||
if (!result.isMockDetected) return
|
if (!result.isMockDetected) return
|
||||||
messageError($q, null, errorMessages.MOCK_DETECTED)
|
messageError($q, '', errorMessages.MOCK_DETECTED)
|
||||||
}
|
}
|
||||||
|
|
||||||
const resetValidation = () => {
|
const resetValidation = () => {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue