完善地图元素查询机制

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

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