diff --git a/src/components/info/info-panel.vue b/src/components/info/info-panel.vue index 03b829d5..f1f059e1 100644 --- a/src/components/info/info-panel.vue +++ b/src/components/info/info-panel.vue @@ -4,6 +4,7 @@ import SidePanelLayout from '@/components/common/side-panel-layout.vue' import { useAppStore } from '@/stores/app.store' import { useMapStore } from '@/stores/map.store' import { storeToRefs } from 'pinia' +import LocationInfo from './location-info.vue' const { t } = useTranslation() const appStore = useAppStore() @@ -22,21 +23,24 @@ const { locationInfo } = storeToRefs(useMapStore()) diff --git a/src/components/info/location-info.vue b/src/components/info/location-info.vue new file mode 100644 index 00000000..81ec4b9a --- /dev/null +++ b/src/components/info/location-info.vue @@ -0,0 +1,109 @@ + + + diff --git a/src/composables/map/location-info.composable.ts b/src/composables/map/location-info.composable.ts index 923b0a12..1f82853b 100644 --- a/src/composables/map/location-info.composable.ts +++ b/src/composables/map/location-info.composable.ts @@ -46,35 +46,39 @@ export default function useLocationInfo() { } }) + map + .getViewport() + .addEventListener('contextmenu', event => event.preventDefault()) + listen(map, 'pointerdown', event => handleClick(event as MapBrowserEvent) ) - const setClickCordinate = (event: MapBrowserEvent) => { + const getClickCoordinate = (event: MapBrowserEvent) => { return map.getEventCoordinate(event.originalEvent) - // TODO reproject ? } const handleClick = function (event: MapBrowserEvent) { - const pixel = event.pixel - - if (event.originalEvent.button === 0) { - // if left mouse click - locationInfo.value = undefined - } + startPixel = event.pixel if (event.originalEvent.button === 2) { // if right mouse click - locationInfo.value = setClickCordinate(event) + locationInfo.value = getClickCoordinate(event) } else if (event.originalEvent.pointerType == 'touch') { window.clearTimeout(holdTimeoutId) - startPixel = pixel holdTimeoutId = window.setTimeout(() => { - locationInfo.value = setClickCordinate(event) + locationInfo.value = getClickCoordinate(event) }) } } - listen(map, 'pointerup', () => { + listen(map, 'pointerup', (event: any) => { + if ( + startPixel && + (event as MapBrowserEvent).originalEvent.button === 0 + ) { + // if left mouse click + locationInfo.value = undefined + } window.clearTimeout(holdTimeoutId) startPixel = null }) diff --git a/src/services/info/location-info.ts b/src/services/info/location-info.ts new file mode 100644 index 00000000..20b9d408 --- /dev/null +++ b/src/services/info/location-info.ts @@ -0,0 +1,96 @@ +import { urlStorage } from '@/services/state-persistor/storage/url-storage' +import { transform } from 'ol/proj' +import { Coordinate } from 'ol/coordinate' +import { Projection } from 'ol/proj' + +export const INFO_PROJECTIONS = { + 'EPSG:2169': 'Luref', + 'EPSG:4326': 'Lon/Lat WGS84', + 'EPSG:4326:DMS': 'Lon/Lat WGS84 DMS', + 'EPSG:4326:DMm': 'Lon/Lat WGS84 DM', + 'EPSG:3263*': 'WGS84 UTM', +} + +const HEMISPHERES = ['EW', 'NS'] + +export function formatCoords( + coords: Coordinate | undefined, + fromCrs: Projection, + format: string +) { + let toCrs = format + const ext = format.split(':')[2] + let utm = '' + if (ext !== undefined) { + toCrs = format.slice(0, format.lastIndexOf(':')) + } + if (format.endsWith('*')) { + const lonlat = transform(coords!, fromCrs, 'EPSG:4326') + toCrs = Math.floor(lonlat[0]) >= 6 ? 'EPSG:32632' : 'EPSG:32631' + utm = ` (UTM${toCrs.slice(-2)}N)` + } + const newCoords = transform(coords!, fromCrs, toCrs) + if (ext === undefined) { + return ( + newCoords + .map((coord, i) => { + let roundedCoord = Math.round(coord) + if (format === 'EPSG:4326') { + roundedCoord = Math.round(coord * 1e6) / 1e6 + } + const hemisphere = + roundedCoord > 0 ? HEMISPHERES[i][0] : HEMISPHERES[i][1] + return `${Math.abs(roundedCoord)} ${hemisphere}` + }) + .join(' | ') + utm + ) + } + return newCoords + .map((degrees, i) => { + const normalizedDegrees = ((degrees + 180) % 360) - 180 + const hemisphere = + normalizedDegrees > 0 ? HEMISPHERES[i][0] : HEMISPHERES[i][1] + const absDegrees = Math.abs(normalizedDegrees) + const intDegrees = Math.floor(absDegrees) + const minutes = (absDegrees % 1) * 60 + if (ext === 'DMm') { + const roundedMinutes = Math.round(minutes * 1e6) / 1e6 + return `${intDegrees}\u00b0 ${roundedMinutes}\u2032 ${hemisphere}` + } + if (ext === 'DMS') { + const intMinutes = Math.floor(minutes) + const seconds = Math.round((minutes % 1) * 600) / 10 + return `${intDegrees}\u00b0 ${intMinutes}\u2032 ${seconds}\u2033 ${hemisphere}` + } + }) + .join(' | ') +} + +export async function create_short_url(opt_coordinate: Coordinate | undefined) { + return (await urlStorage.getShortUrl(opt_coordinate)).short_url +} + +export function getQRUrl(shortUrl: string | undefined) { + return shortUrl && `https://migration.geoportail.lu/qr?url=${shortUrl}` +} + +export async function getElevation(coords: Coordinate) { + const resp = await fetch( + `https://migration.geoportail.lu/raster?lat=${coords[1]}&lon=${coords[0]}` + ) + const json = await resp.json() + return `${json.dhm} m` +} + +export async function getNearestAddress(coords: Coordinate) { + const resp = await fetch( + `https://migration.geoportail.lu/geocode/reverse?easting=${coords[0]}&northing=${coords[1]}` + ) + const json = await resp.json() + const nearestAddress = json.results[0] + const formattedAddress = `${nearestAddress.number}, ${nearestAddress.street}, ${nearestAddress.postal_code} ${nearestAddress.locality}` + return { + formattedAddress, + distance: `${Math.round(nearestAddress.distance * 100) / 100} m`, + } +} diff --git a/src/services/state-persistor/storage/url-storage.ts b/src/services/state-persistor/storage/url-storage.ts index 59ff1a35..1bd98980 100644 --- a/src/services/state-persistor/storage/url-storage.ts +++ b/src/services/state-persistor/storage/url-storage.ts @@ -18,6 +18,45 @@ export class UrlStorage implements Storage { throw new Error('Method key() not implemented. ' + index) } + getStrippedUrl(opt_coordinate: number[] | undefined) { + // stripped by embedded app parameters + const url = new URL(window.location.toString()) + const params = new URLSearchParams(url.search) + + if (opt_coordinate !== undefined) { + params.set('X', Math.round(opt_coordinate[0]).toString()) + params.set('Y', Math.round(opt_coordinate[1]).toString()) + } + params.delete('localforage') + params.delete('applogin') + params.delete('ipv6') + params.delete('embeddedserver') + + url.search = params.toString() + + return url.toString() + } + + async getShortUrl(opt_coordinate: number[] | undefined) { + const strippedUrl = this.getStrippedUrl(opt_coordinate) + + const data = new URLSearchParams() + data.set('url', strippedUrl.replace('5173', '8080')) + + const response = await fetch( + 'https://migration.geoportail.lu/short/create', + { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + body: data.toString(), + } + ) + + return await response.json() + } + getSnappedUrl() { return this.snappedUrl }