为图层添加属性;新增水流动画图层的显示隐藏

This commit is contained in:
JIANG
2025-11-19 16:10:40 +08:00
parent 538b9fe177
commit 1ca2e80645
5 changed files with 356 additions and 62 deletions

View File

@@ -12,7 +12,8 @@ import View from "ol/View.js";
import "ol/ol.css";
import MapTools from "./MapTools";
import { Layer } from "ol/layer"; // 保留导入,但用于继承
// 导入 DeckLayer
import { DeckLayer } from "@utils/layers";
import VectorTileSource from "ol/source/VectorTile";
import WebGLVectorTileLayer from "ol/layer/WebGLVectorTile";
import MVT from "ol/format/MVT";
@@ -55,28 +56,6 @@ interface DataContextType {
scadaData?: any[]; // SCADA 数据
}
// 创建自定义Layer类来包装deck.gl
class DeckLayer extends Layer {
private deck: Deck;
constructor(deckInstance: Deck) {
super({});
this.deck = deckInstance;
}
render(frameState: any): HTMLElement {
const { size, viewState } = frameState;
const [width, height] = size;
const [longitude, latitude] = toLonLat(viewState.center);
const zoom = viewState.zoom - 1; // 调整 zoom 以匹配
const bearing = (-viewState.rotation * 180) / Math.PI;
const deckViewState = { bearing, longitude, latitude, zoom };
this.deck.setProps({ width, height, viewState: deckViewState });
this.deck.redraw();
// 返回deck.gl的canvas元素
return document.getElementById("deck-canvas") as HTMLElement;
}
}
// 跨组件传递
const MapContext = createContext<OlMap | undefined>(undefined);
const DataContext = createContext<DataContextType | undefined>(undefined);
@@ -107,6 +86,7 @@ export const useData = () => {
const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
const mapRef = useRef<HTMLDivElement | null>(null);
const deckRef = useRef<Deck | null>(null);
const deckFlowRef = useRef<Deck | null>(null);
const [map, setMap] = useState<OlMap>();
// currentCalData 用于存储当前计算结果
@@ -134,6 +114,7 @@ const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
const [junctionText, setJunctionText] = useState("pressure");
const [pipeText, setPipeText] = useState("flow");
const flowAnimation = useRef(false); // 添加动画控制标志
const waterflowUserVisible = useRef<boolean>(true); // 用户设置的水流图层可见性
const [currentZoom, setCurrentZoom] = useState(11); // 当前缩放级别
// 防抖更新函数
@@ -648,6 +629,15 @@ const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
}, 0);
};
map.getView().on("change", handleViewChange);
// 初始化当前缩放级别并强制触发瓦片加载
setTimeout(() => {
const initialZoom = map.getView().getZoom() || 11;
setCurrentZoom(initialZoom);
// 强制触发地图渲染,让瓦片加载事件触发
map.render();
}, 100);
// 初始化 deck.gl
const deck = new Deck({
initialViewState: {
@@ -664,6 +654,32 @@ const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
// deckLayer.setZIndex(1000); // 确保在最上层
map.addLayer(deckLayer);
// 初始化水流动画的 deck.gl
const deckFlow = new Deck({
initialViewState: {
longitude: 0,
latitude: 0,
zoom: 1,
},
canvas: "deck-flow-canvas",
controller: false,
layers: [],
});
deckFlowRef.current = deckFlow;
const deckFlowLayer = new DeckLayer(deckFlow);
deckFlowLayer.set("name", "水流动画");
deckFlowLayer.set("value", "waterflow");
deckFlowLayer.set("type", "animation");
// 初始化用户可见性状态(默认为 true
deckFlowLayer.initUserVisibility("waterflowLayer", true);
// 设置可见性变化回调,同步更新 waterflowUserVisible
deckFlowLayer.setVisibilityChangeCallback((layerId, visible) => {
if (layerId === "waterflowLayer") {
waterflowUserVisible.current = visible;
}
});
map.addLayer(deckFlowLayer);
// 清理函数
return () => {
junctionsLayer.un("change:visible", handleJunctionVisibilityChange);
@@ -671,6 +687,7 @@ const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
map.setTarget(undefined);
map.dispose();
deck.finalize();
deckFlow.finalize();
};
}, []);
@@ -769,7 +786,10 @@ const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
getColor: [0, 220, 255],
opacity: 0.8,
visible:
flowAnimation.current && currentZoom >= 12 && currentZoom <= 24,
waterflowUserVisible.current &&
flowAnimation.current &&
currentZoom >= 12 &&
currentZoom <= 24,
widthMinPixels: 5,
jointRounded: true, // 拐角变圆
// capRounded: true, // 端点变圆
@@ -810,6 +830,75 @@ const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
flowAnimation.current = false;
}
}, [currentPipeCalData, pipeText]);
// 水流动画循环
useEffect(() => {
const deckFlow = deckFlowRef.current;
if (!deckFlow || !flowAnimation.current || pipeData.length === 0) {
// 如果不需要动画,清空图层
if (deckFlow) {
deckFlow.setProps({ layers: [] });
}
return;
}
let animationId: number;
const animate = () => {
if (!deckFlow || !flowAnimation.current) return;
if (pipeData.length === 0) {
animationId = requestAnimationFrame(animate);
return;
}
// 动画总时长(秒)
const animationDuration = 10;
// 缓冲时间(秒)
const bufferTime = 2;
// 完整循环周期
const loopLength = animationDuration + bufferTime;
// 确保时间范围与你的时间戳数据匹配
const currentTime = (Date.now() / 1000) % loopLength; // (0,12) 之间循环
const waterflowLayer = new TripsLayer({
id: "waterflowLayer",
data: pipeData,
getPath: (d) => d.path,
getTimestamps: (d) => {
return d.timestamps; // 这些应该是与 currentTime 匹配的数值
},
getColor: [0, 220, 255],
opacity: 0.8,
visible:
waterflowUserVisible.current &&
flowAnimation.current &&
currentZoom >= 12 &&
currentZoom <= 24,
widthMinPixels: 5,
jointRounded: true, // 拐角变圆
// capRounded: true, // 端点变圆
trailLength: 2, // 水流尾迹淡出时间
currentTime: currentTime,
});
deckFlow.setProps({
layers: [waterflowLayer],
});
// 继续请求动画帧,每帧执行一次函数
animationId = requestAnimationFrame(animate);
};
animate();
// 清理函数
return () => {
if (animationId) {
cancelAnimationFrame(animationId);
}
if (deckFlow) {
deckFlow.setProps({ layers: [] });
}
};
}, [flowAnimation, pipeData, currentZoom]);
// 计算值更新时,更新 junctionData 和 pipeData
useEffect(() => {
const junctionProperties = junctionText;
@@ -890,6 +979,7 @@ const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
{children}
</div>
<canvas id="deck-canvas" />
<canvas id="deck-flow-canvas" />
</MapContext.Provider>
</DataContext.Provider>
</>