map-offline/src/components/Map.vue

162 lines
4.1 KiB
Vue
Raw Normal View History

2023-07-26 16:55:19 +08:00
<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>