完善地图元素查询机制

This commit is contained in:
JIANG
2025-10-31 16:30:32 +08:00
parent b332a6437d
commit 82fb3e1581
4 changed files with 254 additions and 45 deletions

View File

@@ -347,7 +347,7 @@ const Toolbar: React.FC<ToolbarProps> = ({ hiddenButtons, queryType }) => {
// 从要素属性中提取属性面板需要的数据 // 从要素属性中提取属性面板需要的数据
const getFeatureProperties = useCallback(() => { const getFeatureProperties = useCallback(() => {
if (!highlightFeature) return {}; if (!highlightFeature) return {};
const layer = highlightFeature?.getId()?.toString().split(".")[0];
const properties = highlightFeature.getProperties(); const properties = highlightFeature.getProperties();
// 计算属性字段,增加 key 字段 // 计算属性字段,增加 key 字段
const pipeComputedFields = [ const pipeComputedFields = [
@@ -367,7 +367,7 @@ const Toolbar: React.FC<ToolbarProps> = ({ hiddenButtons, queryType }) => {
{ key: "quality", label: "水质", unit: "mg/L" }, { key: "quality", label: "水质", unit: "mg/L" },
]; ];
if (properties.geometry.getType() === "LineString") { if (layer === "geo_pipes_mat" || layer === "geo_pipes") {
let result = { let result = {
id: properties.id, id: properties.id,
type: "管道", type: "管道",
@@ -400,7 +400,7 @@ const Toolbar: React.FC<ToolbarProps> = ({ hiddenButtons, queryType }) => {
} }
return result; return result;
} }
if (properties.geometry.getType() === "Point") { if (layer === "geo_junctions_mat" || layer === "geo_junctions") {
let result = { let result = {
id: properties.id, id: properties.id,
type: "节点", type: "节点",
@@ -432,6 +432,183 @@ const Toolbar: React.FC<ToolbarProps> = ({ hiddenButtons, queryType }) => {
} }
return result; return result;
} }
if (layer === "geo_tanks_mat" || layer === "geo_tanks") {
return {
id: properties.id,
type: "水池",
properties: [
{
label: "海拔",
value: properties.elevation?.toFixed?.(1),
unit: "m",
},
{
label: "初始水位",
value: properties.init_level?.toFixed?.(1),
unit: "m",
},
{
label: "最低水位",
value: properties.min_level?.toFixed?.(1),
unit: "m",
},
{
label: "最高水位",
value: properties.max_level?.toFixed?.(1),
unit: "m",
},
{
label: "直径",
value: properties.diameter?.toFixed?.(1),
unit: "m",
},
{
label: "最小容积",
value: properties.min_vol?.toFixed?.(1),
unit: "m³",
},
// {
// label: "容积曲线",
// value: properties.vol_curve,
// },
{
label: "溢出",
value: properties.overflow ? "是" : "否",
},
],
};
}
if (layer === "geo_reservoirs_mat" || layer === "geo_reservoirs") {
return {
id: properties.id,
type: "水库",
properties: [
{
label: "水头",
value: properties.head?.toFixed?.(1),
unit: "m",
},
// {
// label: "模式",
// value: properties.pattern,
// },
],
};
}
if (layer === "geo_pumps_mat" || layer === "geo_pumps") {
return {
id: properties.id,
type: "水泵",
properties: [
{ label: "起始节点 ID", value: properties.node1 },
{ label: "终点节点 ID", value: properties.node2 },
{
label: "功率",
value: properties.power?.toFixed?.(1),
unit: "kW",
},
{
label: "扬程",
value: properties.head?.toFixed?.(1),
unit: "m",
},
{
label: "转速",
value: properties.speed?.toFixed?.(1),
unit: "rpm",
},
{
label: "模式",
value: properties.pattern,
},
],
};
}
if (layer === "geo_valves_mat" || layer === "geo_valves") {
return {
id: properties.id,
type: "阀门",
properties: [
{ label: "起始节点 ID", value: properties.node1 },
{ label: "终点节点 ID", value: properties.node2 },
{
label: "直径",
value: properties.diameter?.toFixed?.(1),
unit: "mm",
},
{
label: "阀门类型",
value: properties.v_type,
},
// {
// label: "设置",
// value: properties.setting?.toFixed?.(2),
// },
{
label: "局部损失",
value: properties.minor_loss?.toFixed?.(2),
},
],
};
}
// 传输频率文字对应
const getTransmissionFrequency = (transmission_frequency: string) => {
// 传输频率文本00:01:0000:05:0000:10:0000:30:0001:00:00转换为分钟数
const parts = transmission_frequency.split(":");
if (parts.length !== 3) return transmission_frequency;
const hours = parseInt(parts[0], 10);
const minutes = parseInt(parts[1], 10);
const seconds = parseInt(parts[2], 10);
const totalMinutes = hours * 60 + minutes + (seconds >= 30 ? 1 : 0);
return totalMinutes;
};
// 可靠度文字映射
const getReliability = (reliability: number) => {
switch (reliability) {
case 1:
return "高";
case 2:
return "中";
case 3:
return "低";
default:
return "未知";
}
};
if (layer === "geo_scada_mat" || layer === "geo_scada") {
let result = {
id: properties.id,
type: "SCADA设备",
properties: [
{
label: "类型",
value:
properties.type === "pipe_flow" ? "流量传感器" : "压力传感器",
},
{
label: "关联节点 ID",
value: properties.associated_element_id,
},
{
label: "传输模式",
value:
properties.transmission_mode === "non_realtime"
? "定时传输"
: "实时传输",
},
{
label: "传输频率",
value: getTransmissionFrequency(properties.transmission_frequency),
unit: "分钟",
},
{
label: "可靠性",
value: getReliability(properties.reliability),
},
],
};
return result;
}
return {}; return {};
}, [highlightFeature, computedProperties]); }, [highlightFeature, computedProperties]);
@@ -449,7 +626,7 @@ const Toolbar: React.FC<ToolbarProps> = ({ hiddenButtons, queryType }) => {
{!hiddenButtons?.includes("draw") && ( {!hiddenButtons?.includes("draw") && (
<ToolbarButton <ToolbarButton
icon={<EditOutlinedIcon />} icon={<EditOutlinedIcon />}
name="矢量编辑" name="标记绘制"
isActive={activeTools.includes("draw")} isActive={activeTools.includes("draw")}
onClick={() => handleToolClick("draw")} onClick={() => handleToolClick("draw")}
/> />

View File

@@ -189,8 +189,13 @@ const AnalysisParameters: React.FC = () => {
async (event: { coordinate: number[] }) => { async (event: { coordinate: number[] }) => {
if (!map) return; if (!map) return;
const feature = await mapClickSelectFeatures(event, map); const feature = await mapClickSelectFeatures(event, map);
const layer = feature?.getId()?.toString().split(".")[0];
if (!feature) return; if (!feature) return;
if (feature.getGeometry()?.getType() === "Point") { if (
feature.getGeometry()?.getType() === "Point" ||
(layer !== "geo_pipes_mat" && layer !== "geo_pipes")
) {
// 点类型几何不处理 // 点类型几何不处理
open?.({ open?.({
type: "error", type: "error",

View File

@@ -45,6 +45,10 @@ const ZonePropsPanel: React.FC<ZonePropsPanelProps> = ({
} }
}); });
if (clickedFeature) { if (clickedFeature) {
const layer = clickedFeature?.getId()?.toString().split(".")[0];
if (layer !== "network_zone") {
return;
}
setHighlightedFeature(clickedFeature); setHighlightedFeature(clickedFeature);
setProps(clickedFeature.getProperties()); setProps(clickedFeature.getProperties());
// 更新高亮图层 // 更新高亮图层

View File

@@ -17,6 +17,7 @@ import RenderFeature from "ol/render/Feature";
import Map from "ol/Map"; import Map from "ol/Map";
import WebGLVectorTileLayer from "ol/layer/WebGLVectorTile"; import WebGLVectorTileLayer from "ol/layer/WebGLVectorTile";
import VectorTileSource from "ol/source/VectorTile"; import VectorTileSource from "ol/source/VectorTile";
import VectorLayer from "ol/layer/Vector";
// ========== 类型定义 ========== // ========== 类型定义 ==========
@@ -389,55 +390,71 @@ const handleMapClickSelectFeatures = async (
// 获取缩放级别并确保为整数 // 获取缩放级别并确保为整数
let z = Math.floor(view.getZoom() || 0) - 1; let z = Math.floor(view.getZoom() || 0) - 1;
// 获取所有 VectorTileSource
const vectorTileSources = getVectorTileSources(map);
if (!vectorTileSources.length) {
return null;
}
// 存储所有选中的要素 // 存储所有选中的要素
const allSelectedFeatures: Feature[] = []; const allSelectedFeatures: Feature[] = [];
let isFromVectorLayer = false;
// 遍历所有 VectorTileSource // 1. 优先处理 VectorLayer - 使用 forEachFeatureAtPixel
for (const vectorTileSource of vectorTileSources) { const pixel = map.getPixelFromCoordinate(coord);
const tileGrid = vectorTileSource.getTileGrid(); map.forEachFeatureAtPixel(
if (!tileGrid) { pixel,
continue; (feature) => {
// 只处理标准 Feature排除 RenderFeature
// 使用更宽松的检查:检查是否有 getGeometry 方法且不是 RenderFeature
if (feature && !(feature instanceof RenderFeature)) {
allSelectedFeatures.push(feature as Feature);
isFromVectorLayer = true;
} else return false; // 继续遍历所有要素
},
{
hitTolerance: MAP_CONFIG.hitTolerance,
layerFilter: (layer) => layer instanceof VectorLayer,
} }
);
// 调整缩放级别到有效范围 // 2. 如果 VectorLayer 中没有找到要素,再处理 VectorTileSource
const minZoom = tileGrid.getMinZoom(); if (allSelectedFeatures.length === 0) {
const maxZoom = tileGrid.getMaxZoom(); const vectorTileSources = getVectorTileSources(map);
z = clampZoomLevel(z, minZoom, maxZoom); for (const vectorTileSource of vectorTileSources) {
const tileGrid = vectorTileSource.getTileGrid();
if (!tileGrid) {
continue;
}
// 获取瓦片坐标 // 调整缩放级别到有效范围
const tileCoord = tileGrid.getTileCoordForCoordAndZ(coord, z); const minZoom = tileGrid.getMinZoom();
const resolution = tileGrid.getResolution(tileCoord[0]); const maxZoom = tileGrid.getMaxZoom();
z = clampZoomLevel(z, minZoom, maxZoom);
// 创建点击点的缓冲区 // 获取瓦片坐标
const hitPoint = point(toLonLat(coord)); const tileCoord = tileGrid.getTileCoordForCoordAndZ(coord, z);
const buffered = buffer(hitPoint, resolution * MAP_CONFIG.hitTolerance, { const resolution = tileGrid.getResolution(tileCoord[0]);
units: MAP_CONFIG.bufferUnits,
});
// 获取矢量瓦片 // 创建点击点的缓冲区
const vectorRenderTile = vectorTileSource.getTile( const hitPoint = point(toLonLat(coord));
tileCoord[0], const buffered = buffer(hitPoint, resolution * MAP_CONFIG.hitTolerance, {
tileCoord[1], units: MAP_CONFIG.bufferUnits,
tileCoord[2], });
pixelRatio,
projection
);
const vectorTiles = vectorTileSource.getSourceTiles( // 获取矢量瓦片
pixelRatio, const vectorRenderTile = vectorTileSource.getTile(
projection, tileCoord[0],
vectorRenderTile tileCoord[1],
); tileCoord[2],
pixelRatio,
projection
);
// 提取选中的要素 const vectorTiles = vectorTileSource.getSourceTiles(
const selectedFeatures = extractSelectedFeatures(vectorTiles, buffered); pixelRatio,
allSelectedFeatures.push(...selectedFeatures); projection,
vectorRenderTile
);
// 提取选中的要素
const selectedFeatures = extractSelectedFeatures(vectorTiles, buffered);
allSelectedFeatures.push(...selectedFeatures);
}
} }
// 按几何类型优先级排序:点 > 线 > 其他 // 按几何类型优先级排序:点 > 线 > 其他
@@ -445,12 +462,18 @@ const handleMapClickSelectFeatures = async (
classifyFeaturesByGeometry(allSelectedFeatures); classifyFeaturesByGeometry(allSelectedFeatures);
const prioritizedFeatures = [...points, ...lines, ...others]; const prioritizedFeatures = [...points, ...lines, ...others];
// 获取第一个要素的 ID 并查询完整信息 // 获取第一个要素
const firstFeature = prioritizedFeatures[0]; const firstFeature = prioritizedFeatures[0];
if (!firstFeature) { if (!firstFeature) {
return null; return null;
} }
// 如果要素来自 VectorLayer直接返回不需要通过 WFS 查询
if (isFromVectorLayer) {
return firstFeature;
}
// 如果要素来自 VectorTileSource需要通过 WFS 查询完整信息
const queryId = firstFeature.getProperties().id; const queryId = firstFeature.getProperties().id;
if (!queryId) { if (!queryId) {
return null; return null;