完善地图元素查询机制
This commit is contained in:
@@ -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:00,00:05:00,00:10:00,00:30:00,01: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")}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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());
|
||||||
// 更新高亮图层
|
// 更新高亮图层
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user