|
@@ -7,7 +7,8 @@
|
|
ref="regionSelector"
|
|
ref="regionSelector"
|
|
@region-change="handleRegionChange" />
|
|
@region-change="handleRegionChange" />
|
|
</div>
|
|
</div>
|
|
- <div ref="mapContainer" class="map-container"></div>
|
|
|
|
|
|
+ <div ref="mapContainer"
|
|
|
|
+ class="map-container"></div>
|
|
<div v-if="error" class="error">{{ error }}</div>
|
|
<div v-if="error" class="error">{{ error }}</div>
|
|
<!-- 覆盖层控制 -->
|
|
<!-- 覆盖层控制 -->
|
|
<!-- <div class="control-panel">
|
|
<!-- <div class="control-panel">
|
|
@@ -17,6 +18,11 @@
|
|
</label>
|
|
</label>
|
|
</div> -->
|
|
</div> -->
|
|
<div class="control-panel">
|
|
<div class="control-panel">
|
|
|
|
+ <div class="basemap-toggle">
|
|
|
|
+ <button @click="toggleBaseLayer" :class="{ active: isBaseLayer }">
|
|
|
|
+ {{ isBaseLayer ? '纯净地图' : '腾讯地图' }}
|
|
|
|
+ </button>
|
|
|
|
+ </div>
|
|
<label>
|
|
<label>
|
|
<input type="checkbox" v-model="state.showSoilTypes" @change="toggleSoilTypeLayer" />
|
|
<input type="checkbox" v-model="state.showSoilTypes" @change="toggleSoilTypeLayer" />
|
|
显示韶关市评估单元
|
|
显示韶关市评估单元
|
|
@@ -37,7 +43,6 @@
|
|
|
|
|
|
<script setup>
|
|
<script setup>
|
|
import { ref, reactive, onMounted, onBeforeUnmount } from 'vue'
|
|
import { ref, reactive, onMounted, onBeforeUnmount } from 'vue'
|
|
-import axios from 'axios'
|
|
|
|
import html2canvas from 'html2canvas'
|
|
import html2canvas from 'html2canvas'
|
|
import RegionSelector from '@/components/RegionSelector.vue'
|
|
import RegionSelector from '@/components/RegionSelector.vue'
|
|
|
|
|
|
@@ -67,7 +72,6 @@ let soilTypeLayer = null
|
|
let geoJSONLayer;
|
|
let geoJSONLayer;
|
|
let currentInfoWindow = null;
|
|
let currentInfoWindow = null;
|
|
const surveyDataLayer = ref(null); // 保持响应式引用
|
|
const surveyDataLayer = ref(null); // 保持响应式引用
|
|
-let currentLayerId = 0; // 添加图层版本控制[3,4](@ref)
|
|
|
|
let multiPolygon;
|
|
let multiPolygon;
|
|
const districtLayers = ref(new Map()) // 存储区县图层
|
|
const districtLayers = ref(new Map()) // 存储区县图层
|
|
const combinedSurveyFeatures = ref([]); // 存储原始数据
|
|
const combinedSurveyFeatures = ref([]); // 存储原始数据
|
|
@@ -85,6 +89,109 @@ const tMapConfig = reactive({
|
|
geocoderURL: 'https://apis.map.qq.com/ws/geocoder/v1/'
|
|
geocoderURL: 'https://apis.map.qq.com/ws/geocoder/v1/'
|
|
})
|
|
})
|
|
|
|
|
|
|
|
+const isBaseLayer = ref(false)
|
|
|
|
+const layerVisibility = reactive({
|
|
|
|
+ province: false,
|
|
|
|
+ city: false,
|
|
|
|
+ county: false
|
|
|
|
+})
|
|
|
|
+const currentZoom = ref(12)
|
|
|
|
+
|
|
|
|
+// 预加载所有GeoJSON图层
|
|
|
|
+const geoLayers = reactive({
|
|
|
|
+ province: null,
|
|
|
|
+ city: null,
|
|
|
|
+ county: null
|
|
|
|
+})
|
|
|
|
+
|
|
|
|
+const initBaseLayers = async () => {
|
|
|
|
+ try {
|
|
|
|
+ // 按层级加载GeoJSON(需替换实际路径)
|
|
|
|
+ geoLayers.province = await loadAndCreateLayer('/data/省.geojson', 'province')
|
|
|
|
+ geoLayers.city = await loadAndCreateLayer('/data/市.geojson', 'city')
|
|
|
|
+ geoLayers.county = await loadAndCreateLayer('/data/县.geojson', 'county')
|
|
|
|
+
|
|
|
|
+ // 初始化默认状态
|
|
|
|
+ updateLayerVisibility()
|
|
|
|
+ } catch (error) {
|
|
|
|
+ console.error('加载地理数据失败:', error)
|
|
|
|
+ error.value = '地理数据加载失败'
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// 创建带样式的图层
|
|
|
|
+const loadAndCreateLayer = async (url, type) => {
|
|
|
|
+ const geoData = await loadGeoJSON(url)
|
|
|
|
+ return new TMap.value.vector.GeoJSONLayer({
|
|
|
|
+ map: map,
|
|
|
|
+ data: geoData,
|
|
|
|
+ zIndex: 5,
|
|
|
|
+ polygonStyle: new TMap.value.PolygonStyle({
|
|
|
|
+ color: 'rgba(242, 241, 237, 1)',
|
|
|
|
+ borderColor: '#000000',
|
|
|
|
+ borderWidth: 1
|
|
|
|
+ })
|
|
|
|
+ })
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// 智能切换核心方法
|
|
|
|
+const toggleBaseLayer = () => {
|
|
|
|
+ isBaseLayer.value = !isBaseLayer.value
|
|
|
|
+ // 新增地图样式切换逻辑
|
|
|
|
+ if (map) {
|
|
|
|
+ map.setMapStyleId(isBaseLayer.value ? '1' : '0')
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (isBaseLayer.value) {
|
|
|
|
+ map.on('zoom', handleZoomChange)
|
|
|
|
+ updateLayerVisibility()
|
|
|
|
+ } else {
|
|
|
|
+ map.off('zoom', handleZoomChange)
|
|
|
|
+ hideAllLayers()
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// 缩放事件处理
|
|
|
|
+const handleZoomChange = () => {
|
|
|
|
+ currentZoom.value = map.getZoom()
|
|
|
|
+ updateLayerVisibility()
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// 图层可见性逻辑
|
|
|
|
+const updateLayerVisibility = () => {
|
|
|
|
+ const zoom = currentZoom.value
|
|
|
|
+ const rules = [
|
|
|
|
+ { min: 0, max: 5, types: ['province'] },
|
|
|
|
+ { min: 5, max: 10, types: ['city'] },
|
|
|
|
+ { min: 10, max: 20, types: ['county'] }
|
|
|
|
+ ]
|
|
|
|
+
|
|
|
|
+ rules.forEach(rule => {
|
|
|
|
+ const isActive = zoom >= rule.min && zoom <= rule.max
|
|
|
|
+ rule.types.forEach(type => {
|
|
|
|
+ layerVisibility[type] = isActive && isBaseLayer.value
|
|
|
|
+ geoLayers[type]?.setVisible(isActive && isBaseLayer.value)
|
|
|
|
+ })
|
|
|
|
+ })
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+const getLayerColor = (type) => {
|
|
|
|
+ const colors = {
|
|
|
|
+ province: 'rgba(255, 170, 0, 1)',
|
|
|
|
+ city: 'rgba(0, 168, 255, 1)',
|
|
|
|
+ county: 'rgba(76, 175, 80, 1)'
|
|
|
|
+ };
|
|
|
|
+ return colors[type]
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// 清理方法
|
|
|
|
+const hideAllLayers = () => {
|
|
|
|
+ Object.values(geoLayers).forEach(layer => {
|
|
|
|
+ if (layer) layer.setVisible(false)
|
|
|
|
+ })
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
|
|
const loadSDK = () => {
|
|
const loadSDK = () => {
|
|
return new Promise((resolve, reject) => {
|
|
return new Promise((resolve, reject) => {
|
|
@@ -637,7 +744,7 @@ function initMapWithGeoJSON(geojsonData, map) {
|
|
geoJSONLayer = new TMap.value.vector.GeoJSONLayer({
|
|
geoJSONLayer = new TMap.value.vector.GeoJSONLayer({
|
|
map: map,
|
|
map: map,
|
|
data: geojsonData,
|
|
data: geojsonData,
|
|
- zIndex: 1,
|
|
|
|
|
|
+ zIndex: 10,
|
|
polygonStyle: new TMap.value.PolygonStyle({ // 必须用 PolygonStyle 类实例
|
|
polygonStyle: new TMap.value.PolygonStyle({ // 必须用 PolygonStyle 类实例
|
|
color: 'rgba(255, 0, 0, 0.25)',
|
|
color: 'rgba(255, 0, 0, 0.25)',
|
|
showBorder: true,
|
|
showBorder: true,
|
|
@@ -652,7 +759,7 @@ function initMapWithGeoJSON(geojsonData, map) {
|
|
// 高亮选中图层
|
|
// 高亮选中图层
|
|
const highlightLayer = new TMap.value.MultiPolygon({
|
|
const highlightLayer = new TMap.value.MultiPolygon({
|
|
map,
|
|
map,
|
|
- zIndex: 2,
|
|
|
|
|
|
+ zIndex: 20,
|
|
styles: {
|
|
styles: {
|
|
highlight: new TMap.value.PolygonStyle({ // 注意要改为 PolygonStyle
|
|
highlight: new TMap.value.PolygonStyle({ // 注意要改为 PolygonStyle
|
|
color: 'rgba(0, 123, 255, 0.5)', // 半透明蓝色填充
|
|
color: 'rgba(0, 123, 255, 0.5)', // 半透明蓝色填充
|
|
@@ -822,6 +929,7 @@ onMounted(async () => {
|
|
await loadSDK()
|
|
await loadSDK()
|
|
initData()
|
|
initData()
|
|
await initMap()
|
|
await initMap()
|
|
|
|
+ await initBaseLayers()
|
|
} catch (err) {
|
|
} catch (err) {
|
|
error.value = err.message
|
|
error.value = err.message
|
|
}
|
|
}
|
|
@@ -845,10 +953,39 @@ onBeforeUnmount(() => {
|
|
surveyDataLayer.value.setMap(null);
|
|
surveyDataLayer.value.setMap(null);
|
|
surveyDataLayer.value.destroy();
|
|
surveyDataLayer.value.destroy();
|
|
}
|
|
}
|
|
|
|
+ map.off('zoom', handleZoomChange)
|
|
})
|
|
})
|
|
</script>
|
|
</script>
|
|
|
|
|
|
<style scoped>
|
|
<style scoped>
|
|
|
|
+.basemap-toggle {
|
|
|
|
+ margin-top: 8px;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.basemap-toggle button {
|
|
|
|
+ padding: 8px 16px;
|
|
|
|
+ background: #3876ff;
|
|
|
|
+ color: white;
|
|
|
|
+ border: none;
|
|
|
|
+ border-radius: 20px;
|
|
|
|
+ cursor: pointer;
|
|
|
|
+ transition: all 0.3s ease;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.basemap-toggle button:hover {
|
|
|
|
+ background: #2b5dc5;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.basemap-toggle button.active {
|
|
|
|
+ background: #00C853;
|
|
|
|
+ box-shadow: 0 0 8px rgba(0, 200, 83, 0.5);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/* 图层过渡动画 */
|
|
|
|
+.tmap-geojson-layer {
|
|
|
|
+ transition: opacity 0.3s ease, visibility 0.3s ease;
|
|
|
|
+}
|
|
|
|
+
|
|
.map-toolbar {
|
|
.map-toolbar {
|
|
position: relative; /* 确保层级上下文 */
|
|
position: relative; /* 确保层级上下文 */
|
|
z-index: 1000; /* 低于子组件下拉菜单的z-index */
|
|
z-index: 1000; /* 低于子组件下拉菜单的z-index */
|