Commit 21b54bd0 authored by 罗超's avatar 罗超

新增地图组件

parent d2c23c30
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
"@element-plus/icons-vue": "^2.1.0", "@element-plus/icons-vue": "^2.1.0",
"@hcaptcha/vue3-hcaptcha": "^1.3.0", "@hcaptcha/vue3-hcaptcha": "^1.3.0",
"@icon-park/vue-next": "^1.4.2", "@icon-park/vue-next": "^1.4.2",
"@mapbox/mapbox-gl-language": "^1.0.1",
"@types/ali-oss": "^6.16.11", "@types/ali-oss": "^6.16.11",
"@types/opentype.js": "^1.3.8", "@types/opentype.js": "^1.3.8",
"@types/psd": "^3.4.3", "@types/psd": "^3.4.3",
...@@ -33,6 +34,7 @@ ...@@ -33,6 +34,7 @@
"html-to-image": "^1.11.11", "html-to-image": "^1.11.11",
"konva": "^9.3.0", "konva": "^9.3.0",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"mapbox-gl": "^3.6.0",
"md5-ts": "^0.1.6", "md5-ts": "^0.1.6",
"mitt": "^3.0.1", "mitt": "^3.0.1",
"mobile-detect": "^1.4.5", "mobile-detect": "^1.4.5",
......
<template>
<div class="full-width " style="height: 60vh;" id="mapgl_box"></div>
</template>
<script lang="ts" setup>
import MapService from '@/services/MapService';
import MapboxLanguage from '@mapbox/mapbox-gl-language';
import mapboxgl from 'mapbox-gl';
import { onMounted, ref } from 'vue';
const props = withDefaults(defineProps<{
scrollwheelZoom?: boolean
doubleClickZoom?: boolean
}>(), {
scrollwheelZoom: true,
doubleClickZoom: true
})
mapboxgl.accessToken = 'pk.eyJ1IjoiYWxleDkwMTIiLCJhIjoiY2xtOGw4NHdkMGFndTNjcnFkeWZncGc2dyJ9.lVrAdPHE0Dg5zoWFidfj4Q'
const map = ref<mapboxgl.Map>()
const initMapHandle = ()=>{
map.value = new mapboxgl.Map({
container: 'mapgl_box',
style: 'mapbox://styles/alex9012/cm1en7ee8000901prhbv5auuw',
center: [-74.5, 40],
zoom: 10,
maxZoom:11,
minZoom:3,
scrollZoom:props.scrollwheelZoom,
doubleClickZoom:props.doubleClickZoom
});
map.value.addControl(new MapboxLanguage({
defaultLanguage:'zh-Hans'
}))
setTimeout(() => {
map.value?.resize()
}, 500);
// 使用 Mapbox Directions API 计算导航信息
// const directionsClient = map.get
// directionsClient.setOrigin(start);
// directionsClient.setDestination(end);
// directionsClient.on('response', (response) => {
// if (response.routes.length > 0) {
// const route = response.routes[0];
// console.log('导航信息:', route);
// // 可以根据导航信息进行路线绘制等操作
// } else {
// console.error('未找到导航路线。');
// }
// });
// directionsClient.send();
}
const directionsInfoHandle = async ()=>{
// 定义起点和终点坐标
const start = [11.59838875578771,48.1498484882143];
const end = [11.646071564986642,48.157168731123306];
const result = await MapService.queryDirectionsInfoAsync('driving-traffic',start,end)
// 提取导航距离(单位:米)
const distance = result.routes[0].distance;
// 提取用时(单位:秒)
const duration = result.routes[0].duration;
const steps = formatStepsHandle(result.routes[0].legs[0].steps);
console.log(`距离:${formatDistanceHandle(distance)},用时:${formatSecondsAsHHMMSSHandle(duration)}`)
console.log(`步骤如下:`,steps)
}
const formatDistanceHandle=(source:any)=>{
if(isNaN(source)) return '0公里'
source = Math.floor(source)
if(source<1000) return `${source}米`
else return `${(source/1000).toFixed(1)}公里`
}
const formatSecondsAsHHMMSSHandle = (seconds: number): string => {
seconds = Math.floor(seconds)
let hours = Math.floor(seconds / 3600);
let minutes = Math.floor((seconds % 3600) / 60);
let secs = seconds % 60;
hours = hours < 10 ? 0+ hours : hours;
minutes = minutes < 10 ? 0 + minutes : minutes;
secs = secs < 10 ? 0 + secs : secs;
let result = ``
if(hours>0) result = `${hours}小时`
if(minutes>0) result += `${minutes}分钟`
if(secs>0 && result=='') result = `${secs}秒`
return result;
}
const formatStepsHandle = (steps:any[])=>{
let newStep:Array<{durat:string,dist:string,remark:string}> = []
newStep = steps.map((x:any)=>{
return {
dist:formatDistanceHandle(x.distance),
durat:formatSecondsAsHHMMSSHandle(x.duration),
remark:x.maneuver.instruction
}
})
return newStep
}
onMounted(()=>{
initMapHandle()
directionsInfoHandle()
})
</script>
<style>
.mapboxgl-control-container{
display: none!important;
}
</style>
\ No newline at end of file
type profile = 'driving-traffic' |'driving'|'walking' |'cycling'
const token = 'pk.eyJ1IjoiYWxleDkwMTIiLCJhIjoiY2xtOGw4NHdkMGFndTNjcnFkeWZncGc2dyJ9.lVrAdPHE0Dg5zoWFidfj4Q'
class MapService { class MapService {
static queryPlaceInfoAsync = async (keyword: string): Promise<{ label: string, value: string, center: number[] }[]> => { static queryPlaceInfoAsync = async (keyword: string): Promise<{ label: string, value: string, center: number[] }[]> => {
let url = `https://api.mapbox.com/geocoding/v5/mapbox.places/${keyword}.json?types=place&access_token=pk.eyJ1IjoiYWxleDkwMTIiLCJhIjoiY2xtOGw4NHdkMGFndTNjcnFkeWZncGc2dyJ9.lVrAdPHE0Dg5zoWFidfj4Q` let url = `https://api.mapbox.com/geocoding/v5/mapbox.places/${keyword}.json?types=place&access_token=${token}`
const response = await fetch(url) const response = await fetch(url)
return new Promise(async (resolve) => { return new Promise(async (resolve) => {
...@@ -21,6 +24,19 @@ class MapService { ...@@ -21,6 +24,19 @@ class MapService {
resolve([]) resolve([])
}) })
} }
static queryDirectionsInfoAsync = async (profileInfo:profile,start:number[],end:number[])=>{
let url = `https://api.mapbox.com/directions/v5/mapbox/${profileInfo}/${start.join(',')};${end.join(',')}?steps=true&language=zh-CN&access_token=${token}`
console.log(url)
const response = await fetch(url)
if(response.ok){
const data = await response.json()
return data
}
return null
}
} }
export default MapService export default MapService
\ No newline at end of file
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
<div class="row WorkbenchInTab fz14 text-weight-bolder microsoft"> <div class="row WorkbenchInTab fz14 text-weight-bolder microsoft">
<div class="active cusor-pointer">全部</div> <div class="active cusor-pointer">全部</div>
</div> </div>
<div class="WorkbenchInDel fz14 microsoft cusor-pointer"> <div class="WorkbenchInDel fz14 microsoft cusor-pointer" @click="()=>mapVisible=true">
<span>回收站</span> <span>回收站</span>
</div> </div>
</div> </div>
...@@ -168,6 +168,11 @@ ...@@ -168,6 +168,11 @@
</template> </template>
</el-dialog> </el-dialog>
<el-dialog v-model="mapVisible" title="" width="80vw">
<template #header> </template>
<map-view></map-view>
<template #footer> </template>
</el-dialog>
</template> </template>
...@@ -182,18 +187,20 @@ ...@@ -182,18 +187,20 @@
import { ElLoading, ElMessage, ElMessageBox } from "element-plus"; import { ElLoading, ElMessage, ElMessageBox } from "element-plus";
import { injectKeyPublic } from '@/types/injectKey'; import { injectKeyPublic } from '@/types/injectKey';
import ConfigService from '@/services/ConfigService' import ConfigService from '@/services/ConfigService'
import NewProject from './components/NewProject' import MapView from '@/components/Mapbox/MapView.vue';
import NewProject from './components/NewProject.vue'
const router = useRouter() const router = useRouter()
const useMenu = useMenuStore(); //const useMenu = useMenuStore();
const menus = ref(useMenu.getWorkbenchMenu); //const menus = ref(useMenu.getWorkbenchMenu);
const { model } = storeToRefs(useScreenStore()) //const { model } = storeToRefs(useScreenStore())
const addDialogFormVisible = ref(false) const addDialogFormVisible = ref(false)
const dateTime = ref('') const dateTime = ref('')
const dataList = ref([] as Array < any > ); const dataList = ref([] as Array < any > );
const loading = ref(false as any) const loading = ref(false as any)
const deleteLoading = ref<any>(null) const deleteLoading = ref<any>(null)
const mapVisible = ref(false)
const queryObj = reactive({ const queryObj = reactive({
pageIndex: 1, pageIndex: 1,
pageSize: 20, pageSize: 20,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment