162 lines
4.1 KiB
Vue
162 lines
4.1 KiB
Vue
|
<script setup lang="ts">
|
||
|
import { ref, onMounted, provide } from 'vue'
|
||
|
import L from 'leaflet'
|
||
|
import 'leaflet/dist/leaflet.css'
|
||
|
import useCrs from '../hook/useCrs.ts'
|
||
|
import useZoom from '../hook/useZoom.ts'
|
||
|
import { useResizeObserver } from '@vueuse/core'
|
||
|
|
||
|
const mapContainer = ref()
|
||
|
const map = ref<L.Map>()
|
||
|
const layers = ref<L.TileLayer[]>([])
|
||
|
const slotProps = ref({
|
||
|
contextmenu: {}
|
||
|
})
|
||
|
|
||
|
const baiduCrs = useCrs('baiduCrs')
|
||
|
const gaodeCrs = useCrs('gaodeCrs')
|
||
|
|
||
|
const mapFilter = ref('invert(1) grayscale(.2) saturate(0.8) brightness(1.8) opacity(1) hue-rotate(184deg) sepia(17%)'); // 地图滤镜
|
||
|
|
||
|
|
||
|
const mapInfo: Record<string, { crs: L.Proj.CRS | L.CRS, url: string, error: string, center: L.LatLngExpression }> = {
|
||
|
baidu: {
|
||
|
crs: baiduCrs,
|
||
|
url: "http://172.20.10.2/baidumaps/roadmap/{z}/{x}/{y}.png",
|
||
|
error: 'http://172.20.10.2/baidumaps/roadmap/error.png',
|
||
|
center: [39.926474, 116.403283]
|
||
|
},
|
||
|
gaode: {
|
||
|
crs: gaodeCrs,
|
||
|
url: "http://172.20.10.2/mapabc/roadmap/{z}/{x}/{y}.png",
|
||
|
error: 'http://172.20.10.2/baidumaps/roadmap/error.png',
|
||
|
center: [-97.00238024827533, 210.7725501856634]
|
||
|
},
|
||
|
gaodeLine: {
|
||
|
crs: gaodeCrs,
|
||
|
url: "http://webrd02.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}",
|
||
|
error: 'http://172.20.10.2/baidumaps/roadmap/error.png',
|
||
|
center: [-97.00238024827533, 210.7725501856634]
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
provide('map', map) // 注入的内容 mapChild 下
|
||
|
|
||
|
onMounted(() => {
|
||
|
// const selfZoom = useZoom(mapContainer,map, [3,6,9,14,16,18])
|
||
|
|
||
|
// L.Map.addInitHook('addHandler','scrollWheelZoom', selfZoom)
|
||
|
// L.Map.mergeOptions({
|
||
|
// scrollWheelZoom:true
|
||
|
// })
|
||
|
|
||
|
const use: keyof typeof mapInfo = 'gaode'
|
||
|
|
||
|
map.value = L.map(mapContainer.value, {
|
||
|
center: mapInfo[use].center,
|
||
|
zoom: 13,
|
||
|
attributionControl: false,
|
||
|
crs: mapInfo[use].crs,
|
||
|
zoomControl: false,
|
||
|
});
|
||
|
|
||
|
// const scale= L.control.scale({ maxWidth: 200, metric: true, imperial: true });
|
||
|
// map.value.addControl(scale)
|
||
|
const layer = L.tileLayer(mapInfo[use].url, {
|
||
|
minZoom: 3,
|
||
|
maxZoom: 18,
|
||
|
tms: true,
|
||
|
errorTileUrl: mapInfo[use].error,
|
||
|
className: "mapFilter",
|
||
|
})
|
||
|
|
||
|
// map.value.on('zoom', (e) => {
|
||
|
// console.log(e.target._animateToZoom)
|
||
|
// })
|
||
|
|
||
|
layers.value?.push(layer)
|
||
|
|
||
|
layer.addTo(map.value)
|
||
|
|
||
|
map.value.addEventListener("contextmenu", (e) => {
|
||
|
slotProps.value.contextmenu = e
|
||
|
})
|
||
|
|
||
|
})
|
||
|
|
||
|
function flyTo(latLng: [number, number]) {
|
||
|
map.value?.flyTo(L.latLng(latLng[0], latLng[1]))
|
||
|
}
|
||
|
|
||
|
function changeZoom(zoomSize: [number, number]) {
|
||
|
map.value?.setMinZoom(zoomSize[0])
|
||
|
map.value?.setMaxZoom(zoomSize[1])
|
||
|
}
|
||
|
|
||
|
function changeMapFilter(filterInfo: Record<'blur' |
|
||
|
'brightness' |
|
||
|
'contrast' |
|
||
|
'drop-shadow' |
|
||
|
'grayscale' |
|
||
|
'hue-rotate' |
|
||
|
'invert' |
|
||
|
'opacity' |
|
||
|
'saturate' |
|
||
|
'sepia', string | number>) {
|
||
|
mapFilter.value = Object.entries(filterInfo).map(([key, value]) => `${key}(${value})`).join(' ')
|
||
|
}
|
||
|
|
||
|
function changeMapUrl(urlTemplate: string, errorTileUrl: string) {
|
||
|
if (!layers.value[0]) return;
|
||
|
layers.value[0].setUrl(urlTemplate);
|
||
|
layers.value[0].options.errorTileUrl = errorTileUrl;
|
||
|
}
|
||
|
|
||
|
function changeAnimation(zoomAnimation: boolean, fadeAnimation: boolean) {
|
||
|
if (!map.value) return;
|
||
|
map.value.options.zoomAnimation = zoomAnimation
|
||
|
map.value.options.fadeAnimation = fadeAnimation
|
||
|
}
|
||
|
|
||
|
|
||
|
function changeZoomSnap(zoomAnimation: number) {
|
||
|
if (!map.value) return;
|
||
|
map.value.options.zoomSnap = zoomAnimation
|
||
|
}
|
||
|
|
||
|
|
||
|
function pushLayers(addlayers: L.TileLayer[]) {
|
||
|
const _map = map.value
|
||
|
if (!_map) return
|
||
|
addlayers.forEach(l => {
|
||
|
if (_map.hasLayer(l)) return;
|
||
|
layers.value.push(l)
|
||
|
l.addTo(_map)
|
||
|
})
|
||
|
}
|
||
|
|
||
|
useResizeObserver(mapContainer, () => map.value?.invalidateSize(true))
|
||
|
|
||
|
defineExpose({ flyTo, changeZoom, changeMapFilter, changeMapUrl, pushLayers, changeAnimation,changeZoomSnap })
|
||
|
</script>
|
||
|
|
||
|
<template>
|
||
|
<div class="mapContainer" ref="mapContainer" :style="{ '--mapFilter': mapFilter }">
|
||
|
<slot v-if="map" v-bind="slotProps"></slot>
|
||
|
</div>
|
||
|
</template>
|
||
|
|
||
|
<style lang="scss">
|
||
|
.mapContainer {
|
||
|
grid-area: map;
|
||
|
}
|
||
|
|
||
|
body.body--dark {
|
||
|
.mapFilter {
|
||
|
filter: var(--mapFilter);
|
||
|
}
|
||
|
}
|
||
|
</style>
|