测试页面
							parent
							
								
									a7b3afeb64
								
							
						
					
					
						commit
						ca28c0851e
					
				| 
						 | 
					@ -8,7 +8,7 @@ pnpm-debug.log*
 | 
				
			||||||
lerna-debug.log*
 | 
					lerna-debug.log*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
node_modules
 | 
					node_modules
 | 
				
			||||||
dist
 | 
					# dist
 | 
				
			||||||
dist-ssr
 | 
					dist-ssr
 | 
				
			||||||
*.local
 | 
					*.local
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										25
									
								
								README.md
								
								
								
								
							
							
						
						
									
										25
									
								
								README.md
								
								
								
								
							| 
						 | 
					@ -1,8 +1,19 @@
 | 
				
			||||||
## 
 | 
					整理
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // L.tileLayer("http://webrd0{s}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}", {
 | 
					# 配置
 | 
				
			||||||
  //   attribution: '© ',
 | 
					
 | 
				
			||||||
  //   maxZoom: 15,
 | 
					useConfig(map) , 类似的全局配置
 | 
				
			||||||
  //   minZoom: 10,
 | 
					
 | 
				
			||||||
  //   subdomains: "1234"
 | 
					# 地图
 | 
				
			||||||
  // }).addTo(map.value)
 | 
					
 | 
				
			||||||
 | 
					useMap(map,options)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# 图层
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					useTileLayer(map,url,options)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					绘制多个底图
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# 绘制图层
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					useGeoJSON(map,data)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							| 
						 | 
					@ -0,0 +1,15 @@
 | 
				
			||||||
 | 
					<!DOCTYPE html>
 | 
				
			||||||
 | 
					<html lang="en">
 | 
				
			||||||
 | 
					  <head>
 | 
				
			||||||
 | 
					    <meta charset="UTF-8" />
 | 
				
			||||||
 | 
					    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
 | 
				
			||||||
 | 
					    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
 | 
				
			||||||
 | 
					    <title>Vite + Vue + TS</title>
 | 
				
			||||||
 | 
					    <script type="module" crossorigin src="/assets/index-3e0c8030.js"></script>
 | 
				
			||||||
 | 
					    <link rel="stylesheet" href="/assets/index-f637f0ab.css">
 | 
				
			||||||
 | 
					  </head>
 | 
				
			||||||
 | 
					  <body>
 | 
				
			||||||
 | 
					    <div id="app"></div>
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					  </body>
 | 
				
			||||||
 | 
					</html>
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1 @@
 | 
				
			||||||
 | 
					<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
 | 
				
			||||||
| 
		 After Width: | Height: | Size: 1.5 KiB  | 
							
								
								
									
										15
									
								
								src/App.vue
								
								
								
								
							
							
						
						
									
										15
									
								
								src/App.vue
								
								
								
								
							| 
						 | 
					@ -5,9 +5,10 @@ import Mark from './components/mapChild/Mark.vue'
 | 
				
			||||||
import useMarks, { markType } from './hook/useMarks.ts'
 | 
					import useMarks, { markType } from './hook/useMarks.ts'
 | 
				
			||||||
import ThemeSwitch from './components/ThemeSwitch.vue'
 | 
					import ThemeSwitch from './components/ThemeSwitch.vue'
 | 
				
			||||||
import MarkMenu from './components/left/MarkMenu.vue'
 | 
					import MarkMenu from './components/left/MarkMenu.vue'
 | 
				
			||||||
import CtrlMenu, { DataProps } from './components/left/CtrlMenu.vue'
 | 
					import CtrlMenu from './components/left/CtrlMenu.vue'
 | 
				
			||||||
import { mdiLanConnect } from '@quasar/extras/mdi-v7'
 | 
					import { mdiLanConnect } from '@quasar/extras/mdi-v7'
 | 
				
			||||||
import { useWindowSize } from '@vueuse/core';
 | 
					import { useWindowSize } from '@vueuse/core';
 | 
				
			||||||
 | 
					import { Config } from './hook/useConfig';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const map = ref<InstanceType<typeof Map>>(); // 获取地图的实例 纂取实例方法
 | 
					const map = ref<InstanceType<typeof Map>>(); // 获取地图的实例 纂取实例方法
 | 
				
			||||||
| 
						 | 
					@ -15,6 +16,7 @@ const marks = useMarks([{ latlng: [39.92647400, 116.40328300], title: '北京故
 | 
				
			||||||
const tab = ref('mark')
 | 
					const tab = ref('mark')
 | 
				
			||||||
const sideStyle = ref('20em,logo');
 | 
					const sideStyle = ref('20em,logo');
 | 
				
			||||||
const { width } = useWindowSize()
 | 
					const { width } = useWindowSize()
 | 
				
			||||||
 | 
					const mapConfig = ref()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
onBeforeMount(() => {
 | 
					onBeforeMount(() => {
 | 
				
			||||||
  sideStyle.value = width.value > 600 ? '20em,logo' : '0em,bar'
 | 
					  sideStyle.value = width.value > 600 ? '20em,logo' : '0em,bar'
 | 
				
			||||||
| 
						 | 
					@ -37,21 +39,18 @@ function removeMark(index: number) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function flytoMark(index: number) {
 | 
					function flytoMark(index: number) {
 | 
				
			||||||
  map.value?.flyTo(marks.value[index].latlng)
 | 
					  mapConfig.value.center = marks.value[index].latlng
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function ctrlMap(e: DataProps) {
 | 
					function ctrlMap(e: Config) {
 | 
				
			||||||
  const { zoom, errorTileUrl, urlTemplate, zoomSnap } = e;
 | 
					  mapConfig.value = e
 | 
				
			||||||
  map.value?.changeZoom([zoom.min, zoom.max])
 | 
					 | 
				
			||||||
  map.value?.changeMapUrl(urlTemplate, errorTileUrl)
 | 
					 | 
				
			||||||
  map.value?.changeZoomSnap(zoomSnap)
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<template>
 | 
					<template>
 | 
				
			||||||
  <h5 class="logo">离线地图</h5>
 | 
					  <h5 class="logo">离线地图</h5>
 | 
				
			||||||
  <Map ref="map" v-slot="{ contextmenu }">
 | 
					  <Map ref="map" v-slot="{ contextmenu }" v-model="mapConfig">
 | 
				
			||||||
    <q-menu touch-position context-menu>
 | 
					    <q-menu touch-position context-menu>
 | 
				
			||||||
      <q-list dense style="min-width: 100px">
 | 
					      <q-list dense style="min-width: 100px">
 | 
				
			||||||
        <q-item clickable v-close-popup>
 | 
					        <q-item clickable v-close-popup>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,99 +1,37 @@
 | 
				
			||||||
<script setup lang="ts">
 | 
					<script setup lang="ts">
 | 
				
			||||||
import { ref, onMounted, provide } from 'vue'
 | 
					import { ref, onMounted, provide, watch } from 'vue'
 | 
				
			||||||
import L from 'leaflet'
 | 
					 | 
				
			||||||
import 'leaflet/dist/leaflet.css'
 | 
					import 'leaflet/dist/leaflet.css'
 | 
				
			||||||
import useCrs from '../hook/useCrs.ts'
 | 
					import useMap from '../hook/useMap.ts'
 | 
				
			||||||
import useZoom from '../hook/useZoom.ts'
 | 
					 | 
				
			||||||
import { useResizeObserver } from '@vueuse/core'
 | 
					import { useResizeObserver } from '@vueuse/core'
 | 
				
			||||||
 | 
					import { setOptions } from 'leaflet'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const mapContainer = ref()
 | 
					const mapContainer = ref()
 | 
				
			||||||
const map = ref<L.Map>()
 | 
					const { map, tileLayers, props: mapProps } = useMap(mapContainer, { use: 'gaode', zoom: 13 });
 | 
				
			||||||
const layers = ref<L.TileLayer[]>([])
 | 
					
 | 
				
			||||||
 | 
					// const config = defineModel<Object>()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const slotProps = ref({
 | 
					const slotProps = ref({
 | 
				
			||||||
  contextmenu: {}
 | 
					  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 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 下
 | 
					provide('map', map) // 注入的内容 mapChild 下
 | 
				
			||||||
 | 
					
 | 
				
			||||||
onMounted(() => {
 | 
					onMounted(() => {
 | 
				
			||||||
  // const selfZoom = useZoom(mapContainer,map, [3,6,9,14,16,18])
 | 
					  map.value?.addEventListener("contextmenu", (e) => {
 | 
				
			||||||
 | 
					 | 
				
			||||||
  // 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
 | 
					    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])
 | 
					watch({ center: mapProps.value.center }, ({ center }) => center && map.value?.flyTo(center))
 | 
				
			||||||
  map.value?.setMaxZoom(zoomSize[1])
 | 
					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' |
 | 
					function changeMapFilter(filterInfo: Record<'blur' |
 | 
				
			||||||
  'brightness' |
 | 
					  'brightness' |
 | 
				
			||||||
| 
						 | 
					@ -108,38 +46,9 @@ function changeMapFilter(filterInfo: Record<'blur' |
 | 
				
			||||||
  mapFilter.value = Object.entries(filterInfo).map(([key, value]) => `${key}(${value})`).join(' ')
 | 
					  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))
 | 
					useResizeObserver(mapContainer, () => map.value?.invalidateSize(true))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
defineExpose({ flyTo, changeZoom, changeMapFilter, changeMapUrl, pushLayers, changeAnimation,changeZoomSnap })
 | 
					defineExpose({ changeMapFilter, setOptions })
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<template>
 | 
					<template>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,28 +1,39 @@
 | 
				
			||||||
<script lang="ts">
 | 
					<script lang="ts">
 | 
				
			||||||
export type DataProps = { zoom: { min: number, max: number }, urlTemplate: string, errorTileUrl: string ,zoomSnap:number}
 | 
					export type DataProps = { zoom: { min: number, max: number }, urlTemplate: string, errorTileUrl: string, zoomSnap: number }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<script lang="ts" setup>
 | 
					<script lang="ts" setup>
 | 
				
			||||||
import { ref, watch } from 'vue';
 | 
					import { ref, watch } from 'vue';
 | 
				
			||||||
const data = ref<DataProps>({
 | 
					import useConfig from '../../hook/useConfig';
 | 
				
			||||||
    zoom: { min: 3, max: 17 },
 | 
					import { MapType } from '../../lib/mapType';
 | 
				
			||||||
    urlTemplate: 'http://localhost/mapabc/roadmap/{z}/{x}/{y}.png', // TODO 动态化,
 | 
					const _configGetter = useConfig()
 | 
				
			||||||
    errorTileUrl: 'http://localhost/baidumaps/roadmap/error.png',
 | 
					const maptype = ref<MapType>('gaode')
 | 
				
			||||||
    zoomSnap:1,
 | 
					const data = ref(_configGetter('gaode'))
 | 
				
			||||||
})
 | 
					 | 
				
			||||||
const emit = defineEmits(['change'])
 | 
					const emit = defineEmits(['change'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					watch(maptype, v => data.value = _configGetter(v))
 | 
				
			||||||
watch(data, (v) => emit('change', v), { deep: true })
 | 
					watch(data, (v) => emit('change', v), { deep: true })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
<template>
 | 
					<template>
 | 
				
			||||||
    <q-list>
 | 
					    <q-list>
 | 
				
			||||||
 | 
					        <q-item>
 | 
				
			||||||
 | 
					            <q-btn-group push>
 | 
				
			||||||
 | 
					                <q-btn-toggle v-model="maptype" toggle-color="primary" :options="[
 | 
				
			||||||
 | 
					                    { label: '百度', value: 'baidu' },
 | 
				
			||||||
 | 
					                    { label: '高德', value: 'gaode' },
 | 
				
			||||||
 | 
					                    { label: '高德在线', value: 'gaodeLine' }
 | 
				
			||||||
 | 
					                ]" />
 | 
				
			||||||
 | 
					            </q-btn-group>
 | 
				
			||||||
 | 
					        </q-item>
 | 
				
			||||||
        <q-item clickable v-close-popup>
 | 
					        <q-item clickable v-close-popup>
 | 
				
			||||||
            <q-item-section>
 | 
					            <q-item-section>
 | 
				
			||||||
                <q-item-label>缩放控制</q-item-label>
 | 
					                <q-item-label>缩放控制</q-item-label>
 | 
				
			||||||
                <q-item-label caption>
 | 
					                <q-item-label caption>
 | 
				
			||||||
                    <q-range v-model="data.zoom" :min="3" :max="19" color="deep-orange" label-always markers
 | 
					                    <q-range :model-value="{ max: data.maxZoom, min: data.minZoom }"
 | 
				
			||||||
                        switch-label-side />
 | 
					                        @update:model-value="({ max, min }) => { data.maxZoom = max; data.minZoom = min; }" :min="3"
 | 
				
			||||||
 | 
					                        :max="19" color="deep-orange" label-always markers switch-label-side />
 | 
				
			||||||
                </q-item-label>
 | 
					                </q-item-label>
 | 
				
			||||||
                <!-- TODO 控制多图层 ?? 缩放级别减少 直接控制路线等 -->
 | 
					                <!-- TODO 控制多图层 ?? 缩放级别减少 直接控制路线等 -->
 | 
				
			||||||
                <!-- TODO 地图不清楚 -->
 | 
					                <!-- TODO 地图不清楚 -->
 | 
				
			||||||
| 
						 | 
					@ -48,7 +59,7 @@ watch(data, (v) => emit('change', v), { deep: true })
 | 
				
			||||||
            <q-item-section>
 | 
					            <q-item-section>
 | 
				
			||||||
                <q-item-label>缩放倍数</q-item-label>
 | 
					                <q-item-label>缩放倍数</q-item-label>
 | 
				
			||||||
                <q-item-label caption>
 | 
					                <q-item-label caption>
 | 
				
			||||||
                    <q-input v-model.number="data.zoomSnap"  type="number" />
 | 
					                    <q-input v-model.number="data.zoomSnap" type="number" />
 | 
				
			||||||
                </q-item-label>
 | 
					                </q-item-label>
 | 
				
			||||||
            </q-item-section>
 | 
					            </q-item-section>
 | 
				
			||||||
        </q-item>
 | 
					        </q-item>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,31 @@
 | 
				
			||||||
 | 
					import { MapType } from "../lib/mapType";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type Config = L.TileLayerOptions & { urlTemplate: string, center: L.LatLngExpression, zoomSnap?: number }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const mapConfig: Record<MapType, Config> = {
 | 
				
			||||||
 | 
					    baidu: {
 | 
				
			||||||
 | 
					        urlTemplate: "http://localhost/baidumaps/roadmap/{z}/{x}/{y}.png",
 | 
				
			||||||
 | 
					        errorTileUrl: 'http://localhost/baidumaps/roadmap/error.png',
 | 
				
			||||||
 | 
					        center: [39.926474, 116.403283],
 | 
				
			||||||
 | 
					        maxZoom: 15, minZoom: 3
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    gaode: {
 | 
				
			||||||
 | 
					        urlTemplate: "http://localhost/mapabc/roadmap/{z}/{x}/{y}.png",
 | 
				
			||||||
 | 
					        errorTileUrl: 'http://localhost/baidumaps/roadmap/error.png',
 | 
				
			||||||
 | 
					        center: [-97.00238024827533, 210.7725501856634],
 | 
				
			||||||
 | 
					        maxZoom: 15, minZoom: 3
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    gaodeLine: {
 | 
				
			||||||
 | 
					        urlTemplate: "http://webrd02.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}",
 | 
				
			||||||
 | 
					        errorTileUrl: 'http://localhost/baidumaps/roadmap/error.png',
 | 
				
			||||||
 | 
					        center: [-97.00238024827533, 210.7725501856634],
 | 
				
			||||||
 | 
					        maxZoom: 15, minZoom: 3
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function useConfig(): (name: MapType) => Config {
 | 
				
			||||||
 | 
					    return (name) => mapConfig[name]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default useConfig
 | 
				
			||||||
| 
						 | 
					@ -1,10 +1,11 @@
 | 
				
			||||||
import L from 'leaflet'
 | 
					import L from 'leaflet'
 | 
				
			||||||
import 'proj4'
 | 
					import 'proj4'
 | 
				
			||||||
import 'proj4leaflet'
 | 
					import 'proj4leaflet'
 | 
				
			||||||
 | 
					import { MapType } from '../lib/mapType';
 | 
				
			||||||
const _level = 19;
 | 
					const _level = 19;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const crss = {
 | 
					const crss: Record<MapType, L.CRS> = {
 | 
				
			||||||
    baiduCrs: new L.Proj.CRS('EPSG:900913',
 | 
					    baidu: new L.Proj.CRS('EPSG:900913',
 | 
				
			||||||
        '+proj=merc +a=6378206 +b=6356584.314245179 +lat_ts=0.0 +lon_0=0.0 +x_0=0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext  +no_defs',
 | 
					        '+proj=merc +a=6378206 +b=6356584.314245179 +lat_ts=0.0 +lon_0=0.0 +x_0=0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext  +no_defs',
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            resolutions: function () {
 | 
					            resolutions: function () {
 | 
				
			||||||
| 
						 | 
					@ -19,10 +20,11 @@ const crss = {
 | 
				
			||||||
            origin: [0, 0],
 | 
					            origin: [0, 0],
 | 
				
			||||||
            bounds: L.bounds([20037508.342789244, 0], [0, 20037508.342789244])
 | 
					            bounds: L.bounds([20037508.342789244, 0], [0, 20037508.342789244])
 | 
				
			||||||
        }),
 | 
					        }),
 | 
				
			||||||
    gaodeCrs: L.CRS.Simple
 | 
					    gaode: L.CRS.Simple,
 | 
				
			||||||
 | 
					    gaodeLine:L.CRS.EPSG4326
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function useCrs(name: keyof typeof crss) {
 | 
					function useCrs(name: MapType) {
 | 
				
			||||||
    return crss[name]
 | 
					    return crss[name]
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,76 @@
 | 
				
			||||||
 | 
					import L, { Layer } from "leaflet"
 | 
				
			||||||
 | 
					import { Ref, isRef, onMounted, reactive, ref, shallowRef, toRef, triggerRef, watch } from "vue"
 | 
				
			||||||
 | 
					import useCrs from "./useCrs"
 | 
				
			||||||
 | 
					import { MapType } from "../lib/mapType"
 | 
				
			||||||
 | 
					import useConfig, { Config } from "./useConfig"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 地图接口 地图类型
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					interface MapController {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type DefineProps = L.MapOptions & Partial<Config> & { use: MapType }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface DefineExport {
 | 
				
			||||||
 | 
					    map: Ref<L.Map | undefined>
 | 
				
			||||||
 | 
					    tileLayers: Ref<L.TileLayer[]>
 | 
				
			||||||
 | 
					    gridLayers: Ref<L.GridLayer[]>
 | 
				
			||||||
 | 
					    geoJsons: Ref<L.GeoJSON[]>
 | 
				
			||||||
 | 
					    props: Ref<DefineProps>
 | 
				
			||||||
 | 
					    triggerProps: (options: Config) => void
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function useMap(dom: Ref<string | HTMLElement>, props: DefineProps | Ref<DefineProps>): DefineExport {
 | 
				
			||||||
 | 
					    const _props = isRef(props) ? props : shallowRef(props)
 | 
				
			||||||
 | 
					    const _map = ref<L.Map>()
 | 
				
			||||||
 | 
					    const _tileLayers: Ref<L.TileLayer[]> = ref([])
 | 
				
			||||||
 | 
					    const _gridLayers: Ref<L.GridLayer[]> = ref([])
 | 
				
			||||||
 | 
					    const _geos: Ref<L.GeoJSON[]> = ref([])
 | 
				
			||||||
 | 
					    const _configGetter = useConfig()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    onMounted(() => {
 | 
				
			||||||
 | 
					        const _options = _props // FIXME 这里必须要强转嘛
 | 
				
			||||||
 | 
					        if (!_options) return
 | 
				
			||||||
 | 
					        const crs = useCrs(_options.value.use)
 | 
				
			||||||
 | 
					        const _config = _configGetter(_options.value.use)
 | 
				
			||||||
 | 
					        _map.value = L.map(dom.value, { ..._options.value, crs, center: _config.center })
 | 
				
			||||||
 | 
					        const layer = L.tileLayer(_config.urlTemplate, _config);
 | 
				
			||||||
 | 
					        layer.addTo(_map.value)
 | 
				
			||||||
 | 
					        _tileLayers.value.push(layer)
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    watch(_props, (options) => {
 | 
				
			||||||
 | 
					        if (!_map.value) return
 | 
				
			||||||
 | 
					        if (!options) return
 | 
				
			||||||
 | 
					        _map.value.options.crs = useCrs(options.use)
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    watch(_tileLayers, (layers) => {
 | 
				
			||||||
 | 
					        if (!_map.value) return
 | 
				
			||||||
 | 
					        if (layers.length < 1) return
 | 
				
			||||||
 | 
					        const { hasLayer: _has, addLayer: _add } = _map.value
 | 
				
			||||||
 | 
					        layers.forEach(l => !_has(l) && _add(l))
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    watch(_geos, (geos) => {
 | 
				
			||||||
 | 
					        const __map = _map.value
 | 
				
			||||||
 | 
					        if (!__map) return
 | 
				
			||||||
 | 
					        if (geos.length < 1) return
 | 
				
			||||||
 | 
					        geos.forEach(geo => {
 | 
				
			||||||
 | 
					            geo.addTo(__map)
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 修改后激发props
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    function triggerProps(options: Config) {
 | 
				
			||||||
 | 
					        triggerRef(_props)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return { map: _map, props: _props, tileLayers: _tileLayers, gridLayers: _gridLayers, geoJsons: _geos, triggerProps }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default useMap
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,11 @@
 | 
				
			||||||
 | 
					import { MapType } from "../lib/mapType";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function useConfig<T>( configName:T ,type: Record<MapType, T>) { // TODO 对config监听??
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return // TODO 配置
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default useConfig
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,26 @@
 | 
				
			||||||
 | 
					import L from "leaflet"
 | 
				
			||||||
 | 
					import { Ref, onMounted, ref } from "vue"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function useGeoJson(map:Ref<L.Map>,json:GeoJSON.GeoJsonObject|GeoJSON.GeoJsonObject[],){
 | 
				
			||||||
 | 
					    const geoJson = ref<L.GeoJSON>()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    onMounted(()=>{
 | 
				
			||||||
 | 
					        geoJson.value = L.geoJSON(json,)
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function open(){
 | 
				
			||||||
 | 
					        if (!geoJson.value) return;
 | 
				
			||||||
 | 
					        if (!map.value) return;
 | 
				
			||||||
 | 
					        geoJson.value.addTo(map.value)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function close(){
 | 
				
			||||||
 | 
					        if (!geoJson.value) return;
 | 
				
			||||||
 | 
					        if (!map.value) return;
 | 
				
			||||||
 | 
					        geoJson.value.removeFrom(map.value)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return [geoJson,open,close]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default useGeoJson
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,14 @@
 | 
				
			||||||
 | 
					import L from 'leaflet'
 | 
				
			||||||
 | 
					import { Ref, onMounted, ref } from 'vue'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function useMap(mapContainer: Ref<string | HTMLElement>, options: L.MapOptions) {
 | 
				
			||||||
 | 
					    const map = ref<L.Map>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    onMounted(() => {
 | 
				
			||||||
 | 
					        map.value = L.map(mapContainer.value, options)
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return [map]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default useMap
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,26 @@
 | 
				
			||||||
 | 
					import L from "leaflet";
 | 
				
			||||||
 | 
					import { ref, Ref, onMounted } from "vue";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function useTileLayer(map: Ref<L.Map>, url: string, options: L.TileLayerOptions) {
 | 
				
			||||||
 | 
					    const tileLayer = ref<L.TileLayer>()
 | 
				
			||||||
 | 
					    onMounted(() => {
 | 
				
			||||||
 | 
					        tileLayer.value = L.tileLayer(url, options)
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function open() {
 | 
				
			||||||
 | 
					        if (!tileLayer.value) return;
 | 
				
			||||||
 | 
					        if (!map.value) return;
 | 
				
			||||||
 | 
					        tileLayer.value.addTo(map.value)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function close() {
 | 
				
			||||||
 | 
					        if (!tileLayer.value) return;
 | 
				
			||||||
 | 
					        if (!map.value) return;
 | 
				
			||||||
 | 
					        tileLayer.value.removeFrom(map.value)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return [tileLayer, open, close]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default useTileLayer
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1 @@
 | 
				
			||||||
 | 
					export type MapType = 'baidu' | 'gaode' | 'gaodeLine'
 | 
				
			||||||
		Loading…
	
		Reference in New Issue