486 lines
16 KiB
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>
|