map-offline/src/components/Map.vue

63 lines
2.0 KiB
Vue

<script setup lang="ts">
import { ref, onMounted, provide, watch } from 'vue';
import 'leaflet/dist/leaflet.css';
import useMap from '../hook/useMap.ts';
import { useResizeObserver } from '@vueuse/core';
import { setOptions } from 'leaflet';
const mapContainer = ref();
const { map, tileLayers, props: mapProps } = useMap(mapContainer, { use: 'gaode', zoom: 13 });
// const config = defineModel<Object>()
const slotProps = ref({
contextmenu: {},
});
const mapFilter = ref('invert(1) grayscale(.2) saturate(0.8) brightness(1.8) opacity(1) hue-rotate(184deg) sepia(17%)'); // 地图滤镜
provide('map', map); // 注入的内容 mapChild 下
onMounted(() => {
map.value?.addEventListener('contextmenu', (e) => {
slotProps.value.contextmenu = e;
});
});
watch({ center: mapProps.value.center }, ({ center }) => center && map.value?.flyTo(center));
watch({ max: mapProps.value.maxZoom || 0 }, ({ max }) => map.value?.setMaxZoom(max));
watch({ min: mapProps.value.minZoom || 0 }, ({ min }) => map.value?.setMaxZoom(min));
watch({ url: mapProps.value.urlTemplate }, ({ url }) => url && tileLayers.value[0].setUrl(url));
watch({ zoomSnap: mapProps.value.zoomSnap }, ({ zoomSnap }) => map.value && (map.value.options.zoomSnap = zoomSnap));
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(' ');
}
useResizeObserver(mapContainer, () => map.value?.invalidateSize(true));
defineExpose({ changeMapFilter, setOptions });
</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>