hrms-checkin/src/components/AscGISMapTime.vue

486 lines
16 KiB
Vue

<script setup lang="ts">
import { nextTick, onBeforeUnmount, onMounted, shallowRef, ref } from 'vue'
import { loadModules } from 'esri-loader'
import axios from 'axios'
import markerRedUrl from '@/assets/markers/marker-red.svg?url'
const emit = defineEmits(['update:location'])
function updateLocation(latitude: number, longitude: number, namePOI: string) {
// ส่ง event ไปยัง parent component เพื่ออัพเดทค่า props
emit('update:location', latitude, longitude, namePOI)
}
const poiPlaceName = ref<string>('') // ชื่อพื้นที่ใกล้เคียง
// Replace ArcGIS api key
const apiKey = ref<string>(
'YLATgWuywoeRLHn6KImj5rg7UaP8bJoR9jiTldoCVBHlqFIebwMSA5wIXEmcYhwXwMHkmNISEYtUz3x0oiGIIx0bIXXnUwi0OzupoOEtDrQIsRPVtor7gaPpXEmH8TrNaMT3snf6zO_yujHLGzborg-L9aeAjTJn4ndL6f8qFmRzYcX93E2vyA-7XCufLYTRsdTE5Aq-9hnx1q9PmYVMqhAZpL7dWqn3JgO33fRXetk.'
// 'AAPK4f700a4324d04e9f8a1a134e0771ac45FXWawdCl-OotFfr52gz9XKxTDJTpDzw_YYcwbmKDDyAJswf14FoPyw0qBkN64DvP'
)
const zoomMap = ref<number>(18)
const mapViewRef = shallowRef<any>(null)
const mapContainerRef = ref<HTMLElement | null>(null)
const mapRenderKey = ref<number>(0)
let resizeTimer: ReturnType<typeof setTimeout> | null = null
let resizeRetryCount = 0
const MAX_RESIZE_RETRY = 8
const isRecreatingMap = ref<boolean>(false)
function scheduleMapResize() {
if (resizeTimer) {
clearTimeout(resizeTimer)
}
// Delay a little to wait for viewport + CSS layout to settle after rotation.
resizeTimer = setTimeout(async () => {
await nextTick()
if (!mapViewRef.value || !mapContainerRef.value) {
return
}
const container = mapContainerRef.value
const mapView = mapViewRef.value
if (container.clientWidth === 0 || container.clientHeight === 0) {
if (resizeRetryCount < MAX_RESIZE_RETRY) {
resizeRetryCount += 1
scheduleMapResize()
}
return
}
resizeRetryCount = 0
// Force canvas to bind to the current element after repeated rotations.
if (mapView.container !== container) {
mapView.container = null
await nextTick()
mapView.container = container
}
mapView.resize()
mapView
.goTo(
{
center: mapView.center,
zoom: mapView.zoom,
},
{ animate: false }
)
.catch(() => {
// Ignore interruption errors from rapid orientation changes.
})
}, 300)
}
async function initializeMap() {
if (mapViewRef.value || !mapContainerRef.value) {
return
}
try {
// Load modules of ArcGIS
loadModules([
'esri/config',
'esri/Map',
'esri/views/MapView',
'esri/Graphic',
'esri/geometry/Point',
'esri/symbols/PictureMarkerSymbol',
'esri/widgets/Search',
]).then(
async ([
esriConfig,
Map,
MapView,
Graphic,
Point,
PictureMarkerSymbol,
Search,
]) => {
// 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({
basemap: 'streets',
// basemap: 'streets-navigation-vector',
// basemap: 'arcgis-topographic',
// layers: [hillshadeLayer],
})
navigator.geolocation.getCurrentPosition(async (position) => {
const { latitude, longitude } = position.coords
const pointDefult = new Point({
latitude,
longitude,
})
// สร้าง MapView
const mapView = new MapView({
container: mapContainerRef.value, // div ที่จะแสดงแผนที่
map: map,
center: {
latitude: latitude,
longitude: longitude,
}, // Set the initial map center current position
zoom: zoomMap.value, // ระดับการซูม
ui: {
components: [], // Empty array to remove all default UI components
},
})
mapViewRef.value = mapView
// สร้างสัญลักษณ์ของหมุด
const markerSymbol = new PictureMarkerSymbol({
url: markerRedUrl,
width: '32px',
height: '32px',
})
// สร้าง Search widget เพื่อค้นหาสถานที่
const search = new Search({
view: mapView,
popupEnabled: false,
})
// เพิ่ม Search widget ไปยังแผนที่
mapView.ui.add(search, {
position: 'top-right', // ตำแหน่งของ Search widget
})
// ถ้าได้ token จาก กทม. มา
// await axios
// .get(
// 'https://bmagis.bangkok.go.th/portal/sharing/servers/e4732c3a9fe549ab8bc697573b468f68/rest/services/World/GeocodeServer/reverseGeocode/',
// {
// params: {
// f: 'json', // Format JSON response
// distance: 2000,
// category: 'POI',
// location: {
// spatialReference: { wkid: 4326 },
// x: longitude,
// y: latitude,
// },
// token: apiKey.value,
// },
// }
// )
// .then((response) => {
// console.log('poi', response.data.location)
// poiPlaceName.value = response.data.address
// ? response.data.address.PlaceName === ''
// ? response.data.address.ShortLabel
// : response.data.address.PlaceName
// : 'ไม่พบข้อมูล'
// const poiPoint = new Point({
// longitude: response.data.location.x,
// latitude: response.data.location.y,
// })
// updateLocation(latitude, longitude, poiPlaceName.value)
// })
// .catch(async () => {
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)
poiPlaceName.value = response.data.address
? response.data.address.PlaceName === ''
? response.data.address.ShortLabel
: response.data.address.PlaceName
: 'ไม่พบข้อมูล'
updateLocation(longitude, latitude, poiPlaceName.value)
})
// })
let searchMarker: any = null
searchMarker = new Graphic({
geometry: pointDefult,
symbol: markerSymbol,
})
mapView.graphics.add(searchMarker)
// ฟังก์ชันจับการคลิกบนแผนที่
search.on('select-result', async function (event: any) {
const { latitude, longitude } = event.result.extent.center
const point = new Point({
latitude,
longitude,
})
// ลบหมุดเก่า (ถ้ามี)
if (searchMarker) {
mapView.graphics.remove(searchMarker)
}
// สร้างและเพิ่มหมุดใหม่
searchMarker = new Graphic({
geometry: point,
symbol: markerSymbol,
})
if (searchMarker) {
// await axios
// .get(
// 'https://bmagis.bangkok.go.th/portal/sharing/servers/e4732c3a9fe549ab8bc697573b468f68/rest/services/World/GeocodeServer/reverseGeocode/',
// {
// params: {
// f: 'json', // Format JSON response
// distance: 2000,
// category: 'POI',
// location: {
// spatialReference: { wkid: 4326 },
// x: longitude,
// y: latitude,
// },
// token: apiKey.value,
// },
// }
// )
// .then((response) => {
// console.log('poi', response.data.location)
// poiPlaceName.value = response.data.address
// ? response.data.address.PlaceName === ''
// ? response.data.address.ShortLabel
// : response.data.address.PlaceName
// : 'ไม่พบข้อมูล'
// const poiPoint = new Point({
// longitude: response.data.location.x,
// latitude: response.data.location.y,
// })
// updateLocation(latitude, longitude, poiPlaceName.value)
// })
// .catch(async () => {
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)
poiPlaceName.value = response.data.address
? response.data.address.PlaceName === ''
? response.data.address.ShortLabel
: response.data.address.PlaceName
: 'ไม่พบข้อมูล'
updateLocation(longitude, latitude, poiPlaceName.value)
})
// })
}
mapView.graphics.add(searchMarker)
// เคลื่อนไปยังตำแหน่งที่เลือก
mapView.goTo({
target: point,
zoom: zoomMap.value,
})
})
mapView.on('click', async function (event: any) {
const lat = event.mapPoint.latitude
const lon = event.mapPoint.longitude
const point = new Point({
longitude: lon,
latitude: lat,
})
if (!searchMarker) {
searchMarker = new Graphic({
geometry: point,
symbol: markerSymbol,
})
mapView.graphics.add(searchMarker)
} else {
searchMarker.geometry = point // ย้ายหมุดไปยังตำแหน่งใหม่
if (searchMarker) {
// await axios
// .get(
// 'https://bmagis.bangkok.go.th/portal/sharing/servers/e4732c3a9fe549ab8bc697573b468f68/rest/services/World/GeocodeServer/reverseGeocode/',
// {
// params: {
// f: 'json', // Format JSON response
// distance: 2000,
// category: 'POI',
// location: {
// spatialReference: { wkid: 4326 },
// x: lon,
// y: lat,
// },
// token: apiKey.value,
// },
// }
// )
// .then((response) => {
// console.log('poi', response.data.location)
// poiPlaceName.value = response.data.address
// ? response.data.address.PlaceName === ''
// ? response.data.address.ShortLabel
// : response.data.address.PlaceName
// : 'ไม่พบข้อมูล'
// const poiPoint = new Point({
// longitude: response.data.location.x,
// latitude: response.data.location.y,
// })
// updateLocation(latitude, longitude, poiPlaceName.value)
// })
// .catch(async () => {
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: lon,
y: lat,
},
},
}
)
.then((response) => {
// console.log('poi', response.data.location)
poiPlaceName.value = response.data.address
? response.data.address.PlaceName === ''
? response.data.address.ShortLabel
: response.data.address.PlaceName
: 'ไม่พบข้อมูล'
updateLocation(lat, lon, poiPlaceName.value)
})
// })
}
}
mapView.goTo({
target: point,
zoom: zoomMap.value,
})
})
})
}
)
} catch (error) {
console.error('Error loading the map', error)
}
}
async function recreateMapOnOrientationChange() {
if (isRecreatingMap.value) {
return
}
isRecreatingMap.value = true
try {
if (resizeTimer) {
clearTimeout(resizeTimer)
resizeTimer = null
}
if (mapViewRef.value) {
mapViewRef.value.destroy()
mapViewRef.value = null
}
mapRenderKey.value += 1
await nextTick()
await initializeMap()
scheduleMapResize()
} finally {
isRecreatingMap.value = false
}
}
onMounted(async () => {
await initializeMap()
window.addEventListener('resize', scheduleMapResize)
window.addEventListener('orientationchange', recreateMapOnOrientationChange)
window.addEventListener('pageshow', scheduleMapResize)
})
onBeforeUnmount(() => {
window.removeEventListener('resize', scheduleMapResize)
window.removeEventListener(
'orientationchange',
recreateMapOnOrientationChange
)
window.removeEventListener('pageshow', scheduleMapResize)
if (resizeTimer) {
clearTimeout(resizeTimer)
resizeTimer = null
}
if (mapViewRef.value) {
mapViewRef.value.destroy()
mapViewRef.value = null
}
})
</script>
<template>
<q-card bordered flat class="col-12 bg-grey-2 shadow-0">
<div :key="mapRenderKey" ref="mapContainerRef" style="height: 35vh"></div>
<div
:class="
$q.screen.gt.xs
? 'q-pa-xs text-weight-medium text-grey-8'
: 'q-pa-xs text-weight-medium text-grey-8'
"
>
นทใกลเคยง
<span class="q-px-sm">:</span>
{{ poiPlaceName }}
</div>
</q-card>
</template>
<style></style>