添加栖息地底图
This commit is contained in:
parent
1d1c0a89d8
commit
6a14a4bed0
@ -11,9 +11,9 @@ VITE_APP_BASE_URL = 'http://localhost:8093'
|
|||||||
# 测试环境
|
# 测试环境
|
||||||
# VITE_APP_BASE_URL = 'http://172.16.21.142:8093'
|
# VITE_APP_BASE_URL = 'http://172.16.21.142:8093'
|
||||||
# 汤伟
|
# 汤伟
|
||||||
# VITE_APP_BASE_URL = 'http://10.84.111.235:8093'
|
VITE_APP_BASE_URL = 'http://10.84.111.235:8093'
|
||||||
# 李林
|
# 李林
|
||||||
VITE_APP_BASE_URL = 'http://10.84.111.25:8093'
|
# VITE_APP_BASE_URL = 'http://10.84.111.25:8093'
|
||||||
|
|
||||||
## 开发环境 附件服务地址
|
## 开发环境 附件服务地址
|
||||||
VITE_APP_ATTACHMENT_URL = 'https://211.99.26.225:12125'
|
VITE_APP_ATTACHMENT_URL = 'https://211.99.26.225:12125'
|
||||||
|
|||||||
@ -191,7 +191,7 @@ export const layerConfig2Flat = (data: any): any[] => {
|
|||||||
arr.forEach((item: any) => {
|
arr.forEach((item: any) => {
|
||||||
const { type } = item;
|
const { type } = item;
|
||||||
if (type) {
|
if (type) {
|
||||||
if (type == 'GISMap') {
|
if (type == 'GISMap' || type == 'geojson') {
|
||||||
if (item?.children && item.children.length > 0) {
|
if (item?.children && item.children.length > 0) {
|
||||||
f(item.children);
|
f(item.children);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -11,7 +11,6 @@ import Fill from 'ol/style/Fill';
|
|||||||
import Stroke from 'ol/style/Stroke';
|
import Stroke from 'ol/style/Stroke';
|
||||||
import Icon from 'ol/style/Icon';
|
import Icon from 'ol/style/Icon';
|
||||||
import Text from 'ol/style/Text';
|
import Text from 'ol/style/Text';
|
||||||
import Circle from 'ol/style/Circle';
|
|
||||||
import WMTS from 'ol/source/WMTS';
|
import WMTS from 'ol/source/WMTS';
|
||||||
import WMTSTileGrid from 'ol/tilegrid/WMTS';
|
import WMTSTileGrid from 'ol/tilegrid/WMTS';
|
||||||
import { get as getProjection, fromLonLat } from 'ol/proj';
|
import { get as getProjection, fromLonLat } from 'ol/proj';
|
||||||
@ -77,6 +76,7 @@ export class MapOl implements MapInterface {
|
|||||||
private currentClipGeoJson: any | null = null;
|
private currentClipGeoJson: any | null = null;
|
||||||
private clipRequestController: AbortController | null = null;
|
private clipRequestController: AbortController | null = null;
|
||||||
private hoveredFeatureId: string | number | null = null;
|
private hoveredFeatureId: string | number | null = null;
|
||||||
|
private wfsHighlightLayer: VectorLayer | null = null;
|
||||||
private popupManager: PopupManager;
|
private popupManager: PopupManager;
|
||||||
private regionMaskManager: RegionMaskManager;
|
private regionMaskManager: RegionMaskManager;
|
||||||
private isBatchPopupMode = false;
|
private isBatchPopupMode = false;
|
||||||
@ -166,6 +166,19 @@ export class MapOl implements MapInterface {
|
|||||||
this.popupManager.setMap(this.map);
|
this.popupManager.setMap(this.map);
|
||||||
this.regionMaskManager.setContext(this.map, this.view);
|
this.regionMaskManager.setContext(this.map, this.view);
|
||||||
|
|
||||||
|
// WFS 河段悬停高亮图层:与 demo 项目保持一致,命中要素复制到该图层以加深色描边高亮
|
||||||
|
this.wfsHighlightLayer = new VectorLayer({
|
||||||
|
source: new VectorSource(),
|
||||||
|
style: new Style({
|
||||||
|
stroke: new Stroke({
|
||||||
|
color: '#FFFF00',
|
||||||
|
width: 2
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
zIndex: 20
|
||||||
|
});
|
||||||
|
this.map.addLayer(this.wfsHighlightLayer);
|
||||||
|
|
||||||
this.view.on('change:resolution', () => {
|
this.view.on('change:resolution', () => {
|
||||||
this.handleZoomChange();
|
this.handleZoomChange();
|
||||||
});
|
});
|
||||||
@ -193,12 +206,69 @@ export class MapOl implements MapInterface {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.map.on('pointermove', evt => {
|
this.map.on('pointermove', evt => {
|
||||||
|
// fh_qxd 河段悬停高亮
|
||||||
|
let hitLayer: any = null;
|
||||||
|
const hitFeature = this.map.forEachFeatureAtPixel(
|
||||||
|
evt.pixel,
|
||||||
|
(feature, layer) => {
|
||||||
|
hitLayer = layer;
|
||||||
|
return feature;
|
||||||
|
},
|
||||||
|
{
|
||||||
|
hitTolerance: 0,
|
||||||
|
layerFilter: layer => layer.get('key') === 'fh_qxd'
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// 高亮图层存在时,命中要素复制到高亮图层,未命中则清空
|
||||||
|
if (this.wfsHighlightLayer) {
|
||||||
|
const highlightSource = this.wfsHighlightLayer.getSource();
|
||||||
|
if (hitFeature) {
|
||||||
|
// 根据命中图层的底色动态调整高亮颜色(统一加深)
|
||||||
|
const baseColor = hitLayer?.get('bjColor') || '';
|
||||||
|
// 读取命中图层原始描边宽度,保持高亮只变颜色不加粗
|
||||||
|
let highlightWidth = 5;
|
||||||
|
const layerStyle = hitLayer?.getStyle?.();
|
||||||
|
if (
|
||||||
|
layerStyle &&
|
||||||
|
typeof layerStyle === 'object' &&
|
||||||
|
!Array.isArray(layerStyle)
|
||||||
|
) {
|
||||||
|
const strokeWidth = (layerStyle as Style)
|
||||||
|
.getStroke?.()
|
||||||
|
?.getWidth?.();
|
||||||
|
if (typeof strokeWidth === 'number' && strokeWidth > 0) {
|
||||||
|
highlightWidth = strokeWidth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.wfsHighlightLayer.setStyle(
|
||||||
|
new Style({
|
||||||
|
stroke: new Stroke({
|
||||||
|
color: '#37ff00ff',
|
||||||
|
width: 4
|
||||||
|
})
|
||||||
|
})
|
||||||
|
);
|
||||||
|
highlightSource?.clear();
|
||||||
|
highlightSource?.addFeature(hitFeature);
|
||||||
|
} else {
|
||||||
|
highlightSource?.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 命中河段时直接切换鼠标样式(与 demo 一致,popup 是节流回调不能依赖它)
|
||||||
|
const targetElement = this.map?.getTargetElement() as HTMLElement;
|
||||||
|
if (targetElement) {
|
||||||
|
targetElement.style.cursor = hitFeature ? 'pointer' : '';
|
||||||
|
}
|
||||||
|
|
||||||
this.popupManager.handlePointerMove(evt.pixel, payload => {
|
this.popupManager.handlePointerMove(evt.pixel, payload => {
|
||||||
this.hoveredFeatureId = payload.hoveredId;
|
this.hoveredFeatureId = payload.hoveredId;
|
||||||
|
|
||||||
const targetElement = this.map?.getTargetElement() as HTMLElement;
|
|
||||||
if (targetElement) {
|
if (targetElement) {
|
||||||
targetElement.style.cursor = payload.hoveredId ? 'pointer' : '';
|
// 命中河段或 hover popup 命中锚点时显示 pointer 光标
|
||||||
|
targetElement.style.cursor =
|
||||||
|
payload.hoveredId || hitFeature ? 'pointer' : '';
|
||||||
}
|
}
|
||||||
|
|
||||||
// 批量 popup 模式下不触发 hover popup
|
// 批量 popup 模式下不触发 hover popup
|
||||||
@ -1572,19 +1642,66 @@ export class MapOl implements MapInterface {
|
|||||||
} else {
|
} else {
|
||||||
wmtsLayer.setZIndex(-100);
|
wmtsLayer.setZIndex(-100);
|
||||||
}
|
}
|
||||||
|
wmtsLayer.set('key', layer.key);
|
||||||
wmtsLayer.type = 'layer';
|
wmtsLayer.type = 'layer';
|
||||||
wmtsLayer.setVisible(isShow);
|
wmtsLayer.setVisible(isShow);
|
||||||
this.layerRegistry.set(layer.key, wmtsLayer);
|
this.layerRegistry.set(layer.key, wmtsLayer);
|
||||||
this.map.addLayer(wmtsLayer);
|
this.map.addLayer(wmtsLayer);
|
||||||
layer._layer = wmtsLayer;
|
layer._layer = wmtsLayer;
|
||||||
|
} else if (layer.type === 'wfs') {
|
||||||
|
if (!this.view) return;
|
||||||
|
// 先加载数据,在原始 GeoJSON 层面对坐标做 4326 有效性筛选,删除混入的异常投影数据
|
||||||
|
const isCoordIn4326Range = (lon: number, lat: number) =>
|
||||||
|
lon >= -180 && lon <= 180 && lat >= -90 && lat <= 90;
|
||||||
|
const isValidGeoJsonFeature = (feature: any): boolean => {
|
||||||
|
const geom = feature?.geometry;
|
||||||
|
if (!geom) return false;
|
||||||
|
const flat = geom.coordinates.flat(Infinity) as number[];
|
||||||
|
for (let i = 0; i < flat.length; i += 2) {
|
||||||
|
if (!isCoordIn4326Range(flat[i], flat[i + 1])) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
const vectorSource = new VectorSource();
|
||||||
|
// 先加载数据,过滤异常坐标,再创建图层添加到地图
|
||||||
|
fetch(layer.url)
|
||||||
|
.then(res => res.json())
|
||||||
|
.then(data => {
|
||||||
|
data.features = (data.features || []).filter(isValidGeoJsonFeature);
|
||||||
|
const features = new GeoJSON().readFeatures(data, {
|
||||||
|
// dataProjection: 'EPSG:4326',
|
||||||
|
featureProjection: 'EPSG:3857' // 确保转换到地图使用的投影
|
||||||
|
});
|
||||||
|
vectorSource.addFeatures(features);
|
||||||
|
})
|
||||||
|
.catch(err => console.error(`WFS 图层加载失败 [${layer.key}]:`, err));
|
||||||
|
const wfsLayer = new VectorLayer({
|
||||||
|
source: vectorSource,
|
||||||
|
style: new Style({
|
||||||
|
stroke: new Stroke({
|
||||||
|
color: '#038303',
|
||||||
|
width: 3
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
zIndex: -98,
|
||||||
|
visible: layer.visible !== false
|
||||||
|
});
|
||||||
|
wfsLayer.set('bjColor', layer.color);
|
||||||
|
wfsLayer.set('key', layer.key);
|
||||||
|
wfsLayer.setVisible(isShow);
|
||||||
|
this.layerRegistry.set(layer.key, wfsLayer);
|
||||||
|
this.map.addLayer(wfsLayer);
|
||||||
|
layer._layer = wfsLayer;
|
||||||
} else if (layer.type == 'raster-dem') {
|
} else if (layer.type == 'raster-dem') {
|
||||||
const tileLayer = new TileLayer({
|
const tileLayer = new TileLayer({
|
||||||
source: new XYZ({
|
source: new XYZ({
|
||||||
url: layer.url,
|
url: layer.url,
|
||||||
wrapX: true,
|
wrapX: false,
|
||||||
crossOrigin: 'anonymous'
|
crossOrigin: 'anonymous'
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
tileLayer.set('key', layer.key);
|
||||||
tileLayer.setZIndex(-100);
|
tileLayer.setZIndex(-100);
|
||||||
tileLayer.setVisible(isShow);
|
tileLayer.setVisible(isShow);
|
||||||
tileLayer.type = 'layer';
|
tileLayer.type = 'layer';
|
||||||
|
|||||||
@ -91,9 +91,8 @@ export const useMapOrchestrator = () => {
|
|||||||
// 备注:统一把当前页面中的 GIS 基础图层初始化到地图实例,避免在图层树组件里做配置解析和加层编排。
|
// 备注:统一把当前页面中的 GIS 基础图层初始化到地图实例,避免在图层树组件里做配置解析和加层编排。
|
||||||
const ensureBaseLayersInitialized = (configs: any[] = []) => {
|
const ensureBaseLayersInitialized = (configs: any[] = []) => {
|
||||||
const flatLayerConfigs = layerConfig2Flat(configs);
|
const flatLayerConfigs = layerConfig2Flat(configs);
|
||||||
|
|
||||||
flatLayerConfigs.forEach((item: any) => {
|
flatLayerConfigs.forEach((item: any) => {
|
||||||
if (item.type !== 'GISMap' || !item.key) {
|
if ((item.type !== 'GISMap' && item.type !== 'geojson') || !item.key) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,6 +109,12 @@ export const useMapOrchestrator = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 备注:保证 config.key 与树节点 key 一致,否则 layerRegistry 会注册到错误/空的 key 下,
|
||||||
|
// 导致图层树勾选时 hasBaseLayer 查不到而重复创建图层。
|
||||||
|
if (item.config.key !== item.key) {
|
||||||
|
item.config = { ...item.config, key: item.key };
|
||||||
|
}
|
||||||
|
|
||||||
if (item.key === 'customBaseLayer') {
|
if (item.key === 'customBaseLayer') {
|
||||||
const serializableBaseLayerConfig = {
|
const serializableBaseLayerConfig = {
|
||||||
key: item.config?.key,
|
key: item.config?.key,
|
||||||
@ -134,7 +139,7 @@ export const useMapOrchestrator = () => {
|
|||||||
|
|
||||||
mapClass.controlBaseLayerTreeShowAndHidden(
|
mapClass.controlBaseLayerTreeShowAndHidden(
|
||||||
item.key,
|
item.key,
|
||||||
item.config?.id || item.key,
|
item.config?.key || item.key,
|
||||||
item.checked === 1
|
item.checked === 1
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -781,7 +781,10 @@ export const useMapStore = defineStore('map', () => {
|
|||||||
restoreLayerLegendVisibility(key);
|
restoreLayerLegendVisibility(key);
|
||||||
mapClass.mdLayerTreeShowOrHidden(key, true);
|
mapClass.mdLayerTreeShowOrHidden(key, true);
|
||||||
}
|
}
|
||||||
} else if (layerItem && layerItem.type === 'GISMap') {
|
} else if (
|
||||||
|
layerItem &&
|
||||||
|
(layerItem.type === 'GISMap' || layerItem.type === 'geojson')
|
||||||
|
) {
|
||||||
// 处理 GISMap 类型的图层:勾选时若地图实例中不存在,则先重新加载再控制显隐。
|
// 处理 GISMap 类型的图层:勾选时若地图实例中不存在,则先重新加载再控制显隐。
|
||||||
if (key && key !== '-' && key !== 'powerBaseStation') {
|
if (key && key !== '-' && key !== 'powerBaseStation') {
|
||||||
const shouldBeVisible = checkKeys.includes(key);
|
const shouldBeVisible = checkKeys.includes(key);
|
||||||
@ -900,7 +903,8 @@ export const useMapStore = defineStore('map', () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const allPointData = mapDataStore.rebuildPointDataFromCache(allLayerKeys);
|
const allPointData =
|
||||||
|
mapDataStore.rebuildPointDataFromCache(allLayerKeys);
|
||||||
attachNearbyPointRuntimeMeta(allPointData);
|
attachNearbyPointRuntimeMeta(allPointData);
|
||||||
const runtimeCheckedKeys = getRuntimeCheckedLayerKeys();
|
const runtimeCheckedKeys = getRuntimeCheckedLayerKeys();
|
||||||
const treeCheckedKeys = mapConfigStore.extractCheckedLayerKeys(
|
const treeCheckedKeys = mapConfigStore.extractCheckedLayerKeys(
|
||||||
@ -1084,7 +1088,7 @@ export const useMapStore = defineStore('map', () => {
|
|||||||
legendItem.nameEn
|
legendItem.nameEn
|
||||||
);
|
);
|
||||||
|
|
||||||
if (layerItem?.type === 'GISMap') {
|
if (layerItem?.type === 'GISMap' || layerItem?.type === 'geojson') {
|
||||||
mapClass.controlBaseLayerTreeShowAndHidden(
|
mapClass.controlBaseLayerTreeShowAndHidden(
|
||||||
layerKey,
|
layerKey,
|
||||||
layerItem.config?.id || layerKey,
|
layerItem.config?.id || layerKey,
|
||||||
|
|||||||
@ -1,10 +1,20 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import JidiSelectorMod from "@/modules/jidiSelectorMod.vue";
|
import JidiSelectorMod from '@/modules/jidiSelectorMod.vue';
|
||||||
import RightDrawer from "@/components/RightDrawer/index.vue";
|
import RightDrawer from '@/components/RightDrawer/index.vue';
|
||||||
import QiXiDiBaoHuGongZuoKaiZhan from "@/modules/qixidibaohugongzuokaizhanQK/index.vue"
|
import QiXiDiBaoHuGongZuoKaiZhan from '@/modules/qixidibaohugongzuokaizhanQK/index.vue';
|
||||||
import QixidijchuXx from "@/modules/qixidijchuXx/index.vue"
|
import QixidijchuXx from '@/modules/qixidijchuXx/index.vue';
|
||||||
import QiXiDiShuiWenBianHua from "@/modules/qixidishuiwenbianhua/index.vue"
|
import QiXiDiShuiWenBianHua from '@/modules/qixidishuiwenbianhua/index.vue';
|
||||||
import QiXiDiLiuLiangBianHua from "@/modules/qixidiliuliangbianhua/index.vue"
|
import QiXiDiLiuLiangBianHua from '@/modules/qixidiliuliangbianhua/index.vue';
|
||||||
|
|
||||||
|
import { ref } from 'vue';
|
||||||
|
|
||||||
|
const addMapLayer = () => {
|
||||||
|
console.log('叠加栖息地图层');
|
||||||
|
};
|
||||||
|
|
||||||
|
const showSingle = () => {
|
||||||
|
console.log('单个展示');
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@ -14,6 +24,10 @@ import QiXiDiLiuLiangBianHua from "@/modules/qixidiliuliangbianhua/index.vue"
|
|||||||
</div>
|
</div>
|
||||||
<div class="rightContent">
|
<div class="rightContent">
|
||||||
<RightDrawer>
|
<RightDrawer>
|
||||||
|
<a-button type="primary" @click="addMapLayer">
|
||||||
|
叠加栖息地图层
|
||||||
|
</a-button>
|
||||||
|
<a-button type="primary" @click="showSingle"> 单个展示 </a-button>
|
||||||
<QiXiDiBaoHuGongZuoKaiZhan />
|
<QiXiDiBaoHuGongZuoKaiZhan />
|
||||||
<QiXiDiShuiWenBianHua />
|
<QiXiDiShuiWenBianHua />
|
||||||
<QiXiDiLiuLiangBianHua />
|
<QiXiDiLiuLiangBianHua />
|
||||||
|
|||||||
@ -79,7 +79,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item
|
<a-form-item
|
||||||
label="gisJson"
|
label="地图参数"
|
||||||
name="paramJson"
|
name="paramJson"
|
||||||
v-if="isInterface && formData.type === 'geojson'"
|
v-if="isInterface && formData.type === 'geojson'"
|
||||||
>
|
>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user