perf(map): reuse resources across routes
Preserve standard network layers between map pages while disposing route-owned overlays and controls to prevent memory growth.
This commit is contained in:
@@ -17,24 +17,21 @@ import MapTools from "./MapTools";
|
||||
|
||||
// 导入 DeckLayer
|
||||
import { DeckLayer } from "@utils/layers";
|
||||
import VectorTileSource from "ol/source/VectorTile";
|
||||
import WebGLVectorTileLayer from "ol/layer/WebGLVectorTile";
|
||||
import MVT from "ol/format/MVT";
|
||||
import { FlatStyleLike } from "ol/style/flat";
|
||||
import { toLonLat } from "ol/proj";
|
||||
import { along, bearing, lineString, length, toMercator } from "@turf/turf";
|
||||
import { along, bearing, lineString, length } from "@turf/turf";
|
||||
import { Deck } from "@deck.gl/core";
|
||||
import { TextLayer } from "@deck.gl/layers";
|
||||
import { TripsLayer } from "@deck.gl/geo-layers";
|
||||
import { CollisionFilterExtension } from "@deck.gl/extensions";
|
||||
import VectorSource from "ol/source/Vector";
|
||||
import GeoJson from "ol/format/GeoJSON";
|
||||
import VectorLayer from "ol/layer/Vector";
|
||||
import { Icon, Style } from "ol/style.js";
|
||||
import { FeatureLike } from "ol/Feature";
|
||||
import { Point } from "ol/geom";
|
||||
import { ContourLayer } from "deck.gl";
|
||||
import { toM3h } from "@utils/units";
|
||||
import { usePathname } from "next/navigation";
|
||||
import {
|
||||
cleanupTransientMapResources,
|
||||
disposeMapResources,
|
||||
markMapResourcePersistent,
|
||||
} from "./mapLifecycle";
|
||||
import { createOperationalMapResources } from "./operationalLayers";
|
||||
|
||||
interface MapComponentProps {
|
||||
children?: React.ReactNode;
|
||||
@@ -131,6 +128,7 @@ export const useData = () => {
|
||||
};
|
||||
|
||||
const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
|
||||
const pathname = usePathname();
|
||||
const project = useProject();
|
||||
const MAP_WORKSPACE = project?.workspace || config.MAP_WORKSPACE;
|
||||
const MAP_EXTENT = (project?.extent || config.MAP_EXTENT) as [
|
||||
@@ -371,402 +369,20 @@ const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
|
||||
debouncedUpdateDataRef.current = null;
|
||||
};
|
||||
}, []);
|
||||
// 配置地图数据源、图层和样式
|
||||
const defaultFlatStyle: FlatStyleLike = config.MAP_DEFAULT_STYLE;
|
||||
// 定义 SCADA 图层的样式函数,根据 type 字段选择不同图标
|
||||
const scadaStyle = (feature: any) => {
|
||||
const type = feature.get("type");
|
||||
const scadaPressureIcon = "/icons/scada_pressure.svg";
|
||||
const scadaFlowIcon = "/icons/scada_flow.svg";
|
||||
// 如果 type 不匹配,可以设置默认图标或不显示
|
||||
return new Style({
|
||||
image: new Icon({
|
||||
src: type === "pipe_flow" ? scadaFlowIcon : scadaPressureIcon,
|
||||
scale: 0.1, // 根据需要调整图标大小
|
||||
anchor: [0.5, 0.5], // 图标锚点居中
|
||||
const operationalResources = useMemo(
|
||||
() =>
|
||||
createOperationalMapResources({
|
||||
mapUrl: MAP_URL,
|
||||
workspace: MAP_WORKSPACE,
|
||||
extent: MAP_EXTENT,
|
||||
persistent: true,
|
||||
}),
|
||||
});
|
||||
};
|
||||
// 定义 reservoirs 图层的样式函数,使用固定图标
|
||||
const reservoirStyle = () => {
|
||||
const reserviorIcon = "/icons/reservior.svg";
|
||||
return new Style({
|
||||
image: new Icon({
|
||||
src: reserviorIcon,
|
||||
scale: 0.1, // 根据需要调整图标大小
|
||||
anchor: [0.5, 0.5], // 图标锚点居中
|
||||
}),
|
||||
});
|
||||
};
|
||||
// 定义 tanks 图层的样式函数,使用固定图标
|
||||
const tankStyle = () => {
|
||||
const tankIcon = "/icons/tank.svg";
|
||||
return new Style({
|
||||
image: new Icon({
|
||||
src: tankIcon,
|
||||
scale: 0.1, // 根据需要调整图标大小
|
||||
anchor: [0.5, 0.5], // 图标锚点居中
|
||||
}),
|
||||
});
|
||||
};
|
||||
const valveStyle = {
|
||||
"icon-src": "/icons/valve.svg",
|
||||
"icon-scale": 0.1,
|
||||
};
|
||||
// 定义 pumps 图层的样式函数,使用固定图标
|
||||
const pumpStyle = function (feature: FeatureLike) {
|
||||
const styles = [];
|
||||
const pumpIcon = "/icons/pump.svg";
|
||||
|
||||
const geometry = feature.getGeometry();
|
||||
const lineCoords =
|
||||
geometry?.getType() === "LineString"
|
||||
? (geometry as any).getCoordinates()
|
||||
: null;
|
||||
if (geometry) {
|
||||
const lineCoordsWGS84 = lineCoords.map((coord: []) => {
|
||||
const [lon, lat] = toLonLat(coord);
|
||||
return [lon, lat];
|
||||
});
|
||||
// 计算中点
|
||||
const lineStringFeature = lineString(lineCoordsWGS84);
|
||||
const lineLength = length(lineStringFeature);
|
||||
const midPoint = along(lineStringFeature, lineLength / 2).geometry
|
||||
.coordinates;
|
||||
// 在中点添加 icon 样式
|
||||
const midPointMercator = toMercator(midPoint);
|
||||
styles.push(
|
||||
new Style({
|
||||
geometry: new Point(midPointMercator),
|
||||
image: new Icon({
|
||||
src: pumpIcon,
|
||||
scale: 0.12,
|
||||
anchor: [0.5, 0.5],
|
||||
}),
|
||||
}),
|
||||
);
|
||||
}
|
||||
return styles;
|
||||
};
|
||||
// 矢量瓦片数据源和图层
|
||||
const junctionSource = new VectorTileSource({
|
||||
url: `${MAP_URL}/gwc/service/tms/1.0.0/${MAP_WORKSPACE}:geo_junctions@WebMercatorQuad@pbf/{z}/{x}/{-y}.pbf`, // 替换为你的 MVT 瓦片服务 URL
|
||||
format: new MVT(),
|
||||
projection: "EPSG:3857",
|
||||
});
|
||||
const pipeSource = new VectorTileSource({
|
||||
url: `${MAP_URL}/gwc/service/tms/1.0.0/${MAP_WORKSPACE}:geo_pipes@WebMercatorQuad@pbf/{z}/{x}/{-y}.pbf`, // 替换为你的 MVT 瓦片服务 URL
|
||||
format: new MVT(),
|
||||
projection: "EPSG:3857",
|
||||
});
|
||||
const valveSource = new VectorTileSource({
|
||||
url: `${MAP_URL}/gwc/service/tms/1.0.0/${MAP_WORKSPACE}:geo_valves@WebMercatorQuad@pbf/{z}/{x}/{-y}.pbf`, // 替换为你的 MVT 瓦片服务 URL
|
||||
format: new MVT(),
|
||||
projection: "EPSG:3857",
|
||||
});
|
||||
const reservoirSource = new VectorSource({
|
||||
url: `${MAP_URL}/${MAP_WORKSPACE}/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=${MAP_WORKSPACE}:geo_reservoirs&outputFormat=application/json`,
|
||||
format: new GeoJson(),
|
||||
});
|
||||
const pumpSource = new VectorSource({
|
||||
url: `${MAP_URL}/${MAP_WORKSPACE}/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=${MAP_WORKSPACE}:geo_pumps&outputFormat=application/json`,
|
||||
format: new GeoJson(),
|
||||
});
|
||||
const tankSource = new VectorSource({
|
||||
url: `${MAP_URL}/${MAP_WORKSPACE}/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=${MAP_WORKSPACE}:geo_tanks&outputFormat=application/json`,
|
||||
format: new GeoJson(),
|
||||
});
|
||||
const scadaSource = new VectorSource({
|
||||
url: `${MAP_URL}/${MAP_WORKSPACE}/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=${MAP_WORKSPACE}:geo_scada&outputFormat=application/json`,
|
||||
format: new GeoJson(),
|
||||
});
|
||||
|
||||
// WebGL 渲染优化显示
|
||||
const junctionsLayer = new WebGLVectorTileLayer({
|
||||
source: junctionSource as any, // 使用 WebGL 渲染
|
||||
style: defaultFlatStyle,
|
||||
extent: MAP_EXTENT, // 设置图层范围
|
||||
maxZoom: 24,
|
||||
minZoom: 11,
|
||||
properties: {
|
||||
name: "节点", // 设置图层名称
|
||||
value: "junctions",
|
||||
type: "point",
|
||||
properties: [
|
||||
// { name: "需求量", value: "demand" },
|
||||
{ name: "高程", value: "elevation" },
|
||||
// 计算属性
|
||||
{ name: "实际需水量", value: "actual_demand" },
|
||||
{ name: "水头", value: "total_head" },
|
||||
{ name: "压力", value: "pressure" },
|
||||
{ name: "水质", value: "quality" },
|
||||
],
|
||||
},
|
||||
});
|
||||
const pipesLayer = new WebGLVectorTileLayer({
|
||||
source: pipeSource as any, // 使用 WebGL 渲染
|
||||
style: defaultFlatStyle,
|
||||
extent: MAP_EXTENT, // 设置图层范围
|
||||
maxZoom: 24,
|
||||
minZoom: 11,
|
||||
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: "unit_headloss" },
|
||||
{ name: "水质", value: "quality" },
|
||||
{ name: "反应速率", value: "reaction" },
|
||||
{ name: "设置值", value: "setting" },
|
||||
{ name: "状态", value: "status" },
|
||||
{ name: "流速", value: "velocity" },
|
||||
],
|
||||
},
|
||||
});
|
||||
const valvesLayer = new WebGLVectorTileLayer({
|
||||
source: valveSource as any,
|
||||
style: valveStyle,
|
||||
extent: MAP_EXTENT, // 设置图层范围
|
||||
maxZoom: 24,
|
||||
minZoom: 16,
|
||||
properties: {
|
||||
name: "阀门", // 设置图层名称
|
||||
value: "valves",
|
||||
type: "linestring",
|
||||
properties: [],
|
||||
},
|
||||
});
|
||||
const reservoirsLayer = new VectorLayer({
|
||||
source: reservoirSource,
|
||||
style: reservoirStyle,
|
||||
extent: MAP_EXTENT, // 设置图层范围
|
||||
maxZoom: 24,
|
||||
minZoom: 11,
|
||||
properties: {
|
||||
name: "水库", // 设置图层名称
|
||||
value: "reservoirs",
|
||||
type: "point",
|
||||
properties: [],
|
||||
},
|
||||
});
|
||||
const pumpsLayer = new VectorLayer({
|
||||
source: pumpSource,
|
||||
style: pumpStyle,
|
||||
extent: MAP_EXTENT, // 设置图层范围
|
||||
maxZoom: 24,
|
||||
minZoom: 11,
|
||||
properties: {
|
||||
name: "水泵", // 设置图层名称
|
||||
value: "pumps",
|
||||
type: "linestring",
|
||||
properties: [],
|
||||
},
|
||||
});
|
||||
const tanksLayer = new VectorLayer({
|
||||
source: tankSource,
|
||||
style: tankStyle,
|
||||
extent: MAP_EXTENT, // 设置图层范围
|
||||
maxZoom: 24,
|
||||
minZoom: 11,
|
||||
properties: {
|
||||
name: "水箱", // 设置图层名称
|
||||
value: "tanks",
|
||||
type: "point",
|
||||
properties: [],
|
||||
},
|
||||
});
|
||||
const scadaLayer = new VectorLayer({
|
||||
source: scadaSource,
|
||||
style: scadaStyle,
|
||||
extent: MAP_EXTENT, // 设置图层范围
|
||||
maxZoom: 24,
|
||||
minZoom: 11,
|
||||
properties: {
|
||||
name: "SCADA", // 设置图层名称
|
||||
value: "scada",
|
||||
type: "point",
|
||||
properties: [],
|
||||
},
|
||||
});
|
||||
|
||||
const createOperationalLayers = () => {
|
||||
const nextJunctionSource = new VectorTileSource({
|
||||
url: `${MAP_URL}/gwc/service/tms/1.0.0/${MAP_WORKSPACE}:geo_junctions@WebMercatorQuad@pbf/{z}/{x}/{-y}.pbf`,
|
||||
format: new MVT(),
|
||||
projection: "EPSG:3857",
|
||||
});
|
||||
const nextPipeSource = new VectorTileSource({
|
||||
url: `${MAP_URL}/gwc/service/tms/1.0.0/${MAP_WORKSPACE}:geo_pipes@WebMercatorQuad@pbf/{z}/{x}/{-y}.pbf`,
|
||||
format: new MVT(),
|
||||
projection: "EPSG:3857",
|
||||
});
|
||||
const nextJunctionsLayer = new WebGLVectorTileLayer({
|
||||
source: nextJunctionSource as any,
|
||||
style: defaultFlatStyle,
|
||||
extent: MAP_EXTENT,
|
||||
maxZoom: 24,
|
||||
minZoom: 11,
|
||||
properties: {
|
||||
name: "节点",
|
||||
value: "junctions",
|
||||
type: "point",
|
||||
properties: [
|
||||
{ name: "高程", value: "elevation" },
|
||||
{ name: "实际需水量", value: "actual_demand" },
|
||||
{ name: "水头", value: "total_head" },
|
||||
{ name: "压力", value: "pressure" },
|
||||
{ name: "水质", value: "quality" },
|
||||
],
|
||||
},
|
||||
});
|
||||
const nextPipesLayer = new WebGLVectorTileLayer({
|
||||
source: nextPipeSource as any,
|
||||
style: defaultFlatStyle,
|
||||
extent: MAP_EXTENT,
|
||||
maxZoom: 24,
|
||||
minZoom: 11,
|
||||
properties: {
|
||||
name: "管道",
|
||||
value: "pipes",
|
||||
type: "linestring",
|
||||
properties: [
|
||||
{ name: "管径", value: "diameter" },
|
||||
{ name: "流量", value: "flow" },
|
||||
{ name: "摩阻系数", value: "friction" },
|
||||
{ name: "水头损失", value: "headloss" },
|
||||
{ name: "单位水头损失", value: "unit_headloss" },
|
||||
{ name: "水质", value: "quality" },
|
||||
{ name: "反应速率", value: "reaction" },
|
||||
{ name: "设置值", value: "setting" },
|
||||
{ name: "状态", value: "status" },
|
||||
{ name: "流速", value: "velocity" },
|
||||
],
|
||||
},
|
||||
});
|
||||
const nextValvesLayer = new WebGLVectorTileLayer({
|
||||
source: valveSource as any,
|
||||
style: valveStyle,
|
||||
extent: MAP_EXTENT,
|
||||
maxZoom: 24,
|
||||
minZoom: 16,
|
||||
properties: {
|
||||
name: "阀门",
|
||||
value: "valves",
|
||||
type: "linestring",
|
||||
properties: [],
|
||||
},
|
||||
});
|
||||
const nextReservoirsLayer = new VectorLayer({
|
||||
source: reservoirSource,
|
||||
style: reservoirStyle,
|
||||
extent: MAP_EXTENT,
|
||||
maxZoom: 24,
|
||||
minZoom: 11,
|
||||
properties: {
|
||||
name: "水库",
|
||||
value: "reservoirs",
|
||||
type: "point",
|
||||
properties: [],
|
||||
},
|
||||
});
|
||||
const nextPumpsLayer = new VectorLayer({
|
||||
source: pumpSource,
|
||||
style: pumpStyle,
|
||||
extent: MAP_EXTENT,
|
||||
maxZoom: 24,
|
||||
minZoom: 11,
|
||||
properties: {
|
||||
name: "水泵",
|
||||
value: "pumps",
|
||||
type: "linestring",
|
||||
properties: [],
|
||||
},
|
||||
});
|
||||
const nextTanksLayer = new VectorLayer({
|
||||
source: tankSource,
|
||||
style: tankStyle,
|
||||
extent: MAP_EXTENT,
|
||||
maxZoom: 24,
|
||||
minZoom: 11,
|
||||
properties: {
|
||||
name: "水箱",
|
||||
value: "tanks",
|
||||
type: "point",
|
||||
properties: [],
|
||||
},
|
||||
});
|
||||
const nextScadaLayer = new VectorLayer({
|
||||
source: scadaSource,
|
||||
style: scadaStyle,
|
||||
extent: MAP_EXTENT,
|
||||
maxZoom: 24,
|
||||
minZoom: 11,
|
||||
properties: {
|
||||
name: "SCADA",
|
||||
value: "scada",
|
||||
type: "point",
|
||||
properties: [],
|
||||
},
|
||||
});
|
||||
|
||||
const availableLayers: any[] = [];
|
||||
config.MAP_AVAILABLE_LAYERS.forEach((layerValue) => {
|
||||
switch (layerValue) {
|
||||
case "junctions":
|
||||
availableLayers.push(nextJunctionsLayer);
|
||||
break;
|
||||
case "pipes":
|
||||
availableLayers.push(nextPipesLayer);
|
||||
break;
|
||||
case "valves":
|
||||
availableLayers.push(nextValvesLayer);
|
||||
break;
|
||||
case "reservoirs":
|
||||
availableLayers.push(nextReservoirsLayer);
|
||||
break;
|
||||
case "pumps":
|
||||
availableLayers.push(nextPumpsLayer);
|
||||
break;
|
||||
case "tanks":
|
||||
availableLayers.push(nextTanksLayer);
|
||||
break;
|
||||
case "scada":
|
||||
availableLayers.push(nextScadaLayer);
|
||||
break;
|
||||
}
|
||||
});
|
||||
availableLayers.sort((a, b) => {
|
||||
const order = [
|
||||
"valves",
|
||||
"junctions",
|
||||
"scada",
|
||||
"reservoirs",
|
||||
"pumps",
|
||||
"tanks",
|
||||
"pipes",
|
||||
].reverse();
|
||||
const getValue = (layer: any) => {
|
||||
const props = layer.get ? layer.get("properties") : undefined;
|
||||
return (props && props.value) || layer.get?.("value") || "";
|
||||
};
|
||||
const aVal = getValue(a);
|
||||
const bVal = getValue(b);
|
||||
let ia = order.indexOf(aVal);
|
||||
let ib = order.indexOf(bVal);
|
||||
if (ia === -1) ia = order.length;
|
||||
if (ib === -1) ib = order.length;
|
||||
return ia - ib;
|
||||
});
|
||||
|
||||
return availableLayers;
|
||||
};
|
||||
[MAP_URL, MAP_WORKSPACE, MAP_EXTENT],
|
||||
);
|
||||
const { junctions: junctionSource, pipes: pipeSource } =
|
||||
operationalResources.sources;
|
||||
const { junctions: junctionsLayer, pipes: pipesLayer } =
|
||||
operationalResources.layers;
|
||||
|
||||
// The map and layer instances are intentionally rebuilt only when workspace or extent changes.
|
||||
useEffect(() => {
|
||||
@@ -775,6 +391,8 @@ const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
|
||||
return;
|
||||
}
|
||||
isDisposingRef.current = false;
|
||||
const activeJunctionDataIds = junctionDataIds.current;
|
||||
const activePipeDataIds = pipeDataIds.current;
|
||||
|
||||
const addTimeout = (callback: () => void, delay: number) => {
|
||||
const timerId = window.setTimeout(() => {
|
||||
@@ -927,58 +545,6 @@ const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
|
||||
// 添加事件监听器
|
||||
junctionsLayer.on("change:visible", handleJunctionVisibilityChange);
|
||||
pipesLayer.on("change:visible", handlePipeVisibilityChange);
|
||||
const availableLayers: any[] = [];
|
||||
config.MAP_AVAILABLE_LAYERS.forEach((layerValue) => {
|
||||
switch (layerValue) {
|
||||
case "junctions":
|
||||
availableLayers.push(junctionsLayer);
|
||||
break;
|
||||
case "pipes":
|
||||
availableLayers.push(pipesLayer);
|
||||
break;
|
||||
case "valves":
|
||||
availableLayers.push(valvesLayer);
|
||||
break;
|
||||
case "reservoirs":
|
||||
availableLayers.push(reservoirsLayer);
|
||||
break;
|
||||
case "pumps":
|
||||
availableLayers.push(pumpsLayer);
|
||||
break;
|
||||
case "tanks":
|
||||
availableLayers.push(tanksLayer);
|
||||
break;
|
||||
case "scada":
|
||||
availableLayers.push(scadaLayer);
|
||||
break;
|
||||
}
|
||||
});
|
||||
// 重新排列图层顺序,确保顺序 点>线>面
|
||||
availableLayers.sort((a, b) => {
|
||||
// 明确顺序(点类优先),这里 valves 特殊处理
|
||||
const order = [
|
||||
"valves",
|
||||
"junctions",
|
||||
"scada",
|
||||
"reservoirs",
|
||||
"pumps",
|
||||
"tanks",
|
||||
"pipes",
|
||||
].reverse();
|
||||
// 取值时做安全检查,兼容不同写法(properties.value 或 直接 value)
|
||||
const getValue = (layer: any) => {
|
||||
const props = layer.get ? layer.get("properties") : undefined;
|
||||
return (props && props.value) || layer.get?.("value") || "";
|
||||
};
|
||||
const aVal = getValue(a);
|
||||
const bVal = getValue(b);
|
||||
let ia = order.indexOf(aVal);
|
||||
let ib = order.indexOf(bVal);
|
||||
// 如果未在 order 中找到,放到末尾
|
||||
if (ia === -1) ia = order.length;
|
||||
if (ib === -1) ib = order.length;
|
||||
return ia - ib;
|
||||
});
|
||||
const map = new OlMap({
|
||||
target: mapRef.current,
|
||||
view: new View({
|
||||
@@ -986,9 +552,10 @@ const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
|
||||
projection: "EPSG:3857",
|
||||
}),
|
||||
// 图层依面、线、点、标注次序添加
|
||||
layers: availableLayers.slice(),
|
||||
layers: operationalResources.orderedLayers.slice(),
|
||||
controls: [],
|
||||
});
|
||||
map.getInteractions().forEach(markMapResourcePersistent);
|
||||
setMap(map);
|
||||
|
||||
// 恢复上次视图;如果没有则适配 MAP_EXTENT
|
||||
@@ -1072,10 +639,12 @@ const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
|
||||
controller: false, // 由 OpenLayers 控制视图
|
||||
layers: [],
|
||||
});
|
||||
const deckLayer = new DeckLayer(deck, canvasRef.current, {
|
||||
name: "deckLayer",
|
||||
value: "deckLayer",
|
||||
});
|
||||
const deckLayer = markMapResourcePersistent(
|
||||
new DeckLayer(deck, canvasRef.current, {
|
||||
name: "deckLayer",
|
||||
value: "deckLayer",
|
||||
}),
|
||||
);
|
||||
deckLayerRef.current = deckLayer;
|
||||
setDeckLayer(deckLayer);
|
||||
map.addLayer(deckLayer);
|
||||
@@ -1101,8 +670,13 @@ const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
|
||||
}
|
||||
deckLayerRef.current = null;
|
||||
setDeckLayer(undefined);
|
||||
map.setTarget(undefined);
|
||||
map.dispose();
|
||||
// React Strict Mode re-runs effects with the same memoized layer instances.
|
||||
// Detach and clear them here, but leave final layer/source disposal to GC.
|
||||
disposeMapResources(map, { disposeLayers: false });
|
||||
activeJunctionDataIds.clear();
|
||||
activePipeDataIds.clear();
|
||||
tileJunctionDataBuffer.current = [];
|
||||
tilePipeDataBuffer.current = [];
|
||||
};
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [MAP_WORKSPACE, MAP_EXTENT]);
|
||||
@@ -1117,11 +691,15 @@ const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
|
||||
if (!map || !compareMapRef.current || !compareCanvasRef.current) return;
|
||||
|
||||
isCompareDisposingRef.current = false;
|
||||
const availableLayers = createOperationalLayers();
|
||||
const compareResources = createOperationalMapResources({
|
||||
mapUrl: MAP_URL,
|
||||
workspace: MAP_WORKSPACE,
|
||||
extent: MAP_EXTENT,
|
||||
});
|
||||
const nextCompareMap = new OlMap({
|
||||
target: compareMapRef.current,
|
||||
view: map.getView(),
|
||||
layers: availableLayers.slice(),
|
||||
layers: compareResources.orderedLayers.slice(),
|
||||
controls: [],
|
||||
});
|
||||
nextCompareMap.getAllLayers().forEach((layer) => {
|
||||
@@ -1180,8 +758,7 @@ const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
|
||||
compareDeckLayerRef.current = null;
|
||||
setCompareDeckLayer(undefined);
|
||||
setCompareMap(undefined);
|
||||
nextCompareMap.setTarget(undefined);
|
||||
nextCompareMap.dispose();
|
||||
disposeMapResources(nextCompareMap);
|
||||
};
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [isCompareMode, map]);
|
||||
@@ -1197,6 +774,34 @@ const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
|
||||
};
|
||||
}, [compareMap, isCompareMode, map]);
|
||||
|
||||
useEffect(() => {
|
||||
setCurrentTime(-1);
|
||||
setSelectedDate(new Date());
|
||||
setSchemeName("");
|
||||
setCurrentJunctionCalData([]);
|
||||
setCurrentPipeCalData([]);
|
||||
setCompareJunctionCalData([]);
|
||||
setComparePipeCalData([]);
|
||||
setCompareMode(false);
|
||||
setShowJunctionTextLayer(false);
|
||||
setShowPipeTextLayer(false);
|
||||
setShowJunctionId(false);
|
||||
setShowPipeId(false);
|
||||
setShowContourLayer(false);
|
||||
setContours([]);
|
||||
setContourLayerAvailable(false);
|
||||
setWaterflowLayerAvailable(false);
|
||||
setShowWaterflowLayer(false);
|
||||
setForceStyleAutoApplyVersion(0);
|
||||
|
||||
return () => {
|
||||
if (!map) return;
|
||||
cleanupTransientMapResources(map);
|
||||
deckLayerRef.current?.resetSessionLayers();
|
||||
operationalResources.resetStyles();
|
||||
};
|
||||
}, [pathname, map, operationalResources]);
|
||||
|
||||
// 当数据变化时,更新 deck.gl 图层
|
||||
useEffect(() => {
|
||||
const syncDeckOverlay = (
|
||||
@@ -1348,7 +953,10 @@ const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
|
||||
})
|
||||
: null;
|
||||
|
||||
if (junctionTextLayer && targetDeckLayer.getDeckLayerById("junctionTextLayer")) {
|
||||
if (
|
||||
junctionTextLayer &&
|
||||
targetDeckLayer.getDeckLayerById("junctionTextLayer")
|
||||
) {
|
||||
targetDeckLayer.updateDeckLayer("junctionTextLayer", junctionTextLayer);
|
||||
} else if (junctionTextLayer) {
|
||||
targetDeckLayer.addDeckLayer(junctionTextLayer);
|
||||
@@ -1358,7 +966,10 @@ const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
|
||||
} else if (pipeTextLayer) {
|
||||
targetDeckLayer.addDeckLayer(pipeTextLayer);
|
||||
}
|
||||
if (contourLayer && targetDeckLayer.getDeckLayerById("junctionContourLayer")) {
|
||||
if (
|
||||
contourLayer &&
|
||||
targetDeckLayer.getDeckLayerById("junctionContourLayer")
|
||||
) {
|
||||
targetDeckLayer.updateDeckLayer("junctionContourLayer", contourLayer);
|
||||
} else if (contourLayer) {
|
||||
targetDeckLayer.addDeckLayer(contourLayer);
|
||||
|
||||
Reference in New Issue
Block a user