map-offline/src/App.vue

131 lines
3.7 KiB
Vue
Raw Normal View History

2023-07-26 16:55:19 +08:00
<script setup lang="ts">
import { onBeforeMount, ref, watch } from 'vue';
import Map from './components/Map.vue'
import Mark from './components/mapChild/Mark.vue'
import useMarks, { markType } from './hook/useMarks.ts'
import ThemeSwitch from './components/ThemeSwitch.vue'
import MarkMenu from './components/left/MarkMenu.vue'
import CtrlMenu, { DataProps } from './components/left/CtrlMenu.vue'
import { mdiLanConnect } from '@quasar/extras/mdi-v7'
import { useWindowSize } from '@vueuse/core';
const map = ref<InstanceType<typeof Map>>(); // 获取地图的实例 纂取实例方法
const marks = useMarks([{ latlng: [39.92647400, 116.40328300], title: '北京故宫', opacity: 1 }])
const tab = ref('mark')
const sideStyle = ref('20em,logo');
const { width } = useWindowSize()
onBeforeMount(() => {
sideStyle.value = width.value > 600 ? '20em,logo' : '0em,bar'
})
function changeSide(data: string) {
const _data = data.split(',')
document.body.style.setProperty('--side', _data[0])
document.body.style.setProperty('--logoOrBar', _data[1])
}
watch(sideStyle, changeSide)
function pushMark(params: any, type: markType) {
const { latlng } = params;
marks.value.push({ latlng: [latlng.lat, latlng.lng], title: '新标点', opacity: 1, type })
}
function removeMark(index: number) {
marks.value.splice(index, 1)
}
function flytoMark(index: number) {
map.value?.flyTo(marks.value[index].latlng)
}
function ctrlMap(e: DataProps) {
const { zoom, errorTileUrl, urlTemplate, zoomSnap } = e;
map.value?.changeZoom([zoom.min, zoom.max])
map.value?.changeMapUrl(urlTemplate, errorTileUrl)
map.value?.changeZoomSnap(zoomSnap)
}
</script>
<template>
<h5 class="logo">离线地图</h5>
<Map ref="map" v-slot="{ contextmenu }">
<q-menu touch-position context-menu>
<q-list dense style="min-width: 100px">
<q-item clickable v-close-popup>
<q-item-section @click="pushMark(contextmenu, 'localtion')">添加标点</q-item-section>
</q-item>
<q-item clickable v-close-popup>
<q-item-section @click="pushMark(contextmenu, 'equipment')">添加设备</q-item-section>
</q-item>
</q-list>
</q-menu>
<Mark v-for="(mark, i) in marks" :key="i" :latlng="mark.latlng" :title="mark.title" :opacity="mark.opacity"
:ref="`mark-${i}`">
<template v-if="mark.type === 'equipment'">
<q-icon :name="mdiLanConnect" size="md"></q-icon>
</template>
</Mark>
</Map>
<div class="bar">
<ThemeSwitch></ThemeSwitch>
</div>
<div class="left ">
<q-toggle class="leftctl" v-model="sideStyle" true-value="20em,logo" false-value="0em,bar" />
<q-tabs v-model="tab" dense active-color="primary" indicator-color="primary" align="justify" narrow-indicator>
<q-tab name="mark" label="标点" />
<q-tab name="ctrl" label="控制" />
</q-tabs>
<q-tab-panels v-model="tab" animated keep-alive>
<q-tab-panel name="mark">
<MarkMenu :marks="marks" @flyTo="flytoMark" @remove="removeMark"></MarkMenu>
</q-tab-panel>
<q-tab-panel name="ctrl">
<CtrlMenu @change="ctrlMap"></CtrlMenu>
</q-tab-panel>
</q-tab-panels>
</div>
</template>
<style scoped lang="scss">
.logo {
margin: unset;
grid-area: var(--logoOrBar, logo);
will-change: filter;
transition: filter 300ms;
align-self: center;
text-align: center;
}
.logo:hover {
filter: drop-shadow(0 0 2em #646cffaa);
}
.logo.vue:hover {
filter: drop-shadow(0 0 2em #42b883aa);
}
.left {
grid-area: left;
overflow: auto;
user-select: none;
.leftctl {
position: absolute;
top: 0px;
left: 10px;
}
}
.bar {
grid-area: bar;
display: flex;
align-items: center;
justify-content: flex-end;
margin-right: 20px;
}
</style>