完善时间轴数据更新函数;完善图层显示控制函数;修复图例样式显示异常问题;

This commit is contained in:
JIANG
2025-10-16 17:35:39 +08:00
parent fa0970bd79
commit 665160ae65
5 changed files with 589 additions and 308 deletions

View File

@@ -24,15 +24,18 @@ import { bearing } from "@turf/turf";
import { Deck } from "@deck.gl/core";
import { TextLayer } from "@deck.gl/layers";
import { TripsLayer } from "@deck.gl/geo-layers";
import { el, tr } from "date-fns/locale";
import RenderFeature from "ol/render/Feature";
import { set } from "date-fns";
interface MapComponentProps {
children?: React.ReactNode;
}
interface DataContextType {
junctionData: any[];
pipeData: any[];
setJunctionDataState: React.Dispatch<React.SetStateAction<any[]>>;
setPipeDataState: React.Dispatch<React.SetStateAction<any[]>>;
currentJunctionCalData?: any[]; // 当前计算结果
setCurrentJunctionCalData?: React.Dispatch<React.SetStateAction<any[]>>;
currentPipeCalData?: any[]; // 当前计算结果
setCurrentPipeCalData?: React.Dispatch<React.SetStateAction<any[]>>;
showJunctionText?: boolean; // 是否显示节点文本
showPipeText?: boolean; // 是否显示管道文本
setShowJunctionText?: React.Dispatch<React.SetStateAction<boolean>>;
@@ -96,6 +99,12 @@ const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
const deckRef = useRef<Deck | null>(null);
const [map, setMap] = useState<OlMap>();
// currentCalData 用于存储当前计算结果
const [currentJunctionCalData, setCurrentJunctionCalData] = useState<any[]>(
[]
);
const [currentPipeCalData, setCurrentPipeCalData] = useState<any[]>([]);
// junctionData 和 pipeData 分别缓存瓦片解析后节点和管道的数据,用于 deck.gl 定位、标签渲染
const [junctionData, setJunctionDataState] = useState<any[]>([]);
const [pipeData, setPipeDataState] = useState<any[]>([]);
const junctionDataIds = useRef(new Set<string>());
@@ -105,9 +114,11 @@ const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
const [showJunctionText, setShowJunctionText] = useState(false); // 控制节点文本显示
const [showPipeText, setShowPipeText] = useState(false); // 控制管道文本显示
const [junctionText, setJunctionText] = useState("");
const [pipeText, setPipeText] = useState("");
const flowAnimation = useRef(true); // 添加动画控制标志
const [showJunctionTextLayer, setShowJunctionTextLayer] = useState(true); // 控制节点文本图层显示
const [showPipeTextLayer, setShowPipeTextLayer] = useState(true); // 控制管道文本图层显示
const [junctionText, setJunctionText] = useState("pressure");
const [pipeText, setPipeText] = useState("flow");
const flowAnimation = useRef(false); // 添加动画控制标志
const [currentZoom, setCurrentZoom] = useState(12); // 当前缩放级别
// 防抖更新函数
const debouncedUpdateData = useRef(
@@ -149,37 +160,82 @@ const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
setPipeDataState((prev) => [...prev, ...uniqueNewData]);
}
};
const defaultFlatStyle: FlatStyleLike = {
"stroke-width": 3,
"stroke-color": "rgba(51, 153, 204, 0.9)",
"circle-fill-color": "rgba(255,255,255,0.4)",
"circle-stroke-color": "rgba(255,255,255,0.9)",
"circle-radius": [
"interpolate",
["linear"],
["zoom"],
12,
1, // 在缩放级别 12 时,圆形半径为 1px
24,
12, // 在缩放级别 24 时,圆形半径为 12px
],
};
// 矢量瓦片数据源和图层
const junctionSource = new VectorTileSource({
url: `${mapUrl}/gwc/service/tms/1.0.0/TJWater:geo_junctions_mat@WebMercatorQuad@pbf/{z}/{x}/{-y}.pbf`, // 替换为你的 MVT 瓦片服务 URL
format: new MVT(),
projection: "EPSG:3857",
});
const pipeSource = new VectorTileSource({
url: `${mapUrl}/gwc/service/tms/1.0.0/TJWater:geo_pipes_mat@WebMercatorQuad@pbf/{z}/{x}/{-y}.pbf`, // 替换为你的 MVT 瓦片服务 URL
format: new MVT(),
projection: "EPSG:3857",
});
// WebGL 渲染优化显示
const junctionLayer = new WebGLVectorTileLayer({
source: junctionSource as any, // 使用 WebGL 渲染
style: defaultFlatStyle,
extent: extent, // 设置图层范围
maxZoom: 24,
minZoom: 12,
properties: {
name: "节点图层", // 设置图层名称
value: "junctions",
type: "point",
properties: [
// { name: "需求量", value: "demand" },
// { name: "海拔高度", value: "elevation" },
{ name: "实际需求量", value: "actualdemand" },
{ name: "水头", value: "head" },
{ name: "压力", value: "pressure" },
{ name: "水质", value: "quality" },
],
},
});
const pipeLayer = new WebGLVectorTileLayer({
source: pipeSource as any, // 使用 WebGL 渲染
style: defaultFlatStyle,
extent: extent, // 设置图层范围
maxZoom: 24,
minZoom: 12,
properties: {
name: "管道图层", // 设置图层名称
value: "pipes",
type: "linestring",
properties: [
// { name: "直径", value: "diameter" },
// { name: "粗糙度", value: "roughness" },
// { name: "局部损失", value: "minor_loss" },
{ name: "流量", value: "flow" },
{ name: "摩阻系数", value: "friction" },
{ name: "水头损失", value: "headloss" },
{ name: "水质", value: "quality" },
{ name: "反应速率", value: "reaction" },
{ name: "设置值", value: "setting" },
{ name: "状态", value: "status" },
{ name: "流速", value: "velocity" },
],
},
});
useEffect(() => {
if (!mapRef.current) return;
// 添加 MVT 瓦片加载逻辑
const defaultFlatStyle: FlatStyleLike = {
"stroke-width": 3,
"stroke-color": "rgba(51, 153, 204, 0.9)",
"circle-fill-color": "rgba(255,255,255,0.4)",
"circle-stroke-color": "rgba(255,255,255,0.9)",
"circle-radius": [
"interpolate",
["linear"],
["zoom"],
12,
1, // 在缩放级别 12 时,圆形半径为 1px
24,
12, // 在缩放级别 24 时,圆形半径为 12px
],
};
const junctionSource = new VectorTileSource({
url: `${mapUrl}/gwc/service/tms/1.0.0/TJWater:geo_junctions_mat@WebMercatorQuad@pbf/{z}/{x}/{-y}.pbf`, // 替换为你的 MVT 瓦片服务 URL
format: new MVT(),
projection: "EPSG:3857",
});
const pipeSource = new VectorTileSource({
url: `${mapUrl}/gwc/service/tms/1.0.0/TJWater:geo_pipes_mat@WebMercatorQuad@pbf/{z}/{x}/{-y}.pbf`, // 替换为你的 MVT 瓦片服务 URL
format: new MVT(),
projection: "EPSG:3857",
});
// 缓存数据
// 缓存 junction、pipe 数据,提供给 deck.gl 显示标签使用
junctionSource.on("tileloadend", (event) => {
try {
if (event.tile instanceof VectorTile) {
@@ -290,54 +346,20 @@ const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
console.error("Pipe tile load error:", error);
}
});
// WebGL 渲染优化显示
const junctionLayer = new WebGLVectorTileLayer({
source: junctionSource as any, // 使用 WebGL 渲染
style: defaultFlatStyle,
extent: extent, // 设置图层范围
maxZoom: 24,
minZoom: 12,
properties: {
name: "节点图层", // 设置图层名称
value: "junctions",
type: "point",
properties: [
// { name: "需求量", value: "demand" },
// { name: "海拔高度", value: "elevation" },
{ name: "实际需求量", value: "actualdemand" },
{ name: "水头", value: "head" },
{ name: "压力", value: "pressure" },
{ name: "水质", value: "quality" },
],
},
});
const pipeLayer = new WebGLVectorTileLayer({
source: pipeSource as any, // 使用 WebGL 渲染
style: defaultFlatStyle,
extent: extent, // 设置图层范围
maxZoom: 24,
minZoom: 12,
properties: {
name: "管道图层", // 设置图层名称
value: "pipes",
type: "linestring",
properties: [
// { name: "直径", value: "diameter" },
// { name: "粗糙度", value: "roughness" },
// { name: "局部损失", value: "minor_loss" },
{ name: "流量", value: "flow" },
{ name: "摩阻系数", value: "friction" },
{ name: "水头损失", value: "headloss" },
{ name: "水质", value: "quality" },
{ name: "反应速率", value: "reaction" },
{ name: "设置值", value: "setting" },
{ name: "状态", value: "status" },
{ name: "流速", value: "velocity" },
],
},
});
// 更新标签可见性状态
// 监听 junctionLayer 的 visible 变化
const handleJunctionVisibilityChange = () => {
const isVisible = junctionLayer.getVisible();
setShowJunctionTextLayer(isVisible);
};
// 监听 pipeLayer 的 visible 变化
const handlePipeVisibilityChange = () => {
const isVisible = pipeLayer.getVisible();
setShowPipeTextLayer(isVisible);
};
// 添加事件监听器
junctionLayer.on("change:visible", handleJunctionVisibilityChange);
pipeLayer.on("change:visible", handlePipeVisibilityChange);
const map = new OlMap({
target: mapRef.current,
@@ -375,8 +397,11 @@ const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
const deckLayer = new DeckLayer(deck);
// deckLayer.setZIndex(1000); // 确保在最上层
map.addLayer(deckLayer);
// 清理函数
return () => {
junctionLayer.un("change:visible", handleJunctionVisibilityChange);
pipeLayer.un("change:visible", handlePipeVisibilityChange);
map.setTarget(undefined);
map.dispose();
deck.finalize();
@@ -402,7 +427,8 @@ const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
getTextAnchor: "middle",
getAlignmentBaseline: "center",
getPixelOffset: [0, -10],
visible: currentZoom >= 15 && currentZoom <= 24,
visible:
showJunctionTextLayer && currentZoom >= 15 && currentZoom <= 24,
// --- 修改以下属性 ---
// characterSet: "auto",
// outlineWidth: 4,
@@ -422,7 +448,7 @@ const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
getPixelOffset: [0, -8],
getTextAnchor: "middle",
getAlignmentBaseline: "bottom",
visible: currentZoom >= 15 && currentZoom <= 24,
visible: showPipeTextLayer && currentZoom >= 15 && currentZoom <= 24,
// --- 修改以下属性 ---
// characterSet: "auto",
// outlineWidth: 5,
@@ -456,6 +482,7 @@ const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
},
getColor: [0, 220, 255],
opacity: 0.8,
visible: currentZoom >= 12 && currentZoom <= 24,
widthMinPixels: 5,
jointRounded: true, // 拐角变圆
// capRounded: true, // 端点变圆
@@ -476,16 +503,85 @@ const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
requestAnimationFrame(animate);
};
animate();
}, [flowAnimation, junctionData, pipeData]);
}, [
flowAnimation,
junctionData,
pipeData,
currentZoom,
showJunctionText,
showPipeText,
showJunctionTextLayer,
showPipeTextLayer,
junctionText,
pipeText,
]);
useEffect(() => {
if (pipeText === "flow") {
flowAnimation.current = true;
} else {
flowAnimation.current = false;
}
}, [pipeText]);
// 计算值更新时,更新 junctionData 和 pipeData
useEffect(() => {
const junctionProperties = junctionText;
const pipeProperties = pipeText;
// 将 nodeRecords 转换为 Map 以提高查找效率
const nodeMap: Map<string, any> = new Map(
currentJunctionCalData.map((r: any) => [r.ID, r])
);
// 将 linkRecords 转换为 Map 以提高查找效率
const linkMap: Map<string, any> = new Map(
currentPipeCalData.map((r: any) => [r.ID, r])
);
// 更新junctionData
setJunctionDataState((prev: any[]) =>
prev.map((j) => {
const record = nodeMap.get(j.id);
if (record) {
return {
...j,
[junctionProperties]: record.value,
};
}
return j;
})
);
// 更新pipeData
setPipeDataState((prev: any[]) =>
prev.map((p) => {
const record = linkMap.get(p.id);
if (record) {
return {
...p,
flowFlag: pipeProperties === "flow" && record.value < 0 ? -1 : 1,
path:
pipeProperties === "flow" && record.value < 0 && p.flowFlag > 0
? [...p.path].reverse()
: p.path,
[pipeProperties]: record.value,
};
}
return p;
})
);
}, [currentJunctionCalData, currentPipeCalData]);
return (
<>
<DataContext.Provider
value={{
junctionData,
pipeData,
setJunctionDataState,
setPipeDataState,
currentJunctionCalData,
setCurrentJunctionCalData,
currentPipeCalData,
setCurrentPipeCalData,
setShowJunctionText,
setShowPipeText,
setJunctionText,
setPipeText,
showJunctionText,
showPipeText,
junctionText,