更新 deckLayer 类
This commit is contained in:
@@ -49,6 +49,7 @@ interface DataContextType {
|
||||
showPipeText?: boolean; // 是否显示管道文本
|
||||
setShowJunctionText?: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
setShowPipeText?: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
setShowContourLayer?: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
junctionText: string;
|
||||
pipeText: string;
|
||||
setJunctionText?: React.Dispatch<React.SetStateAction<string>>;
|
||||
@@ -86,7 +87,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 deckLayerRef = useRef<DeckLayer | null>(null);
|
||||
|
||||
const [map, setMap] = useState<OlMap>();
|
||||
// currentCalData 用于存储当前计算结果
|
||||
@@ -111,10 +112,10 @@ const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
|
||||
const [showPipeText, setShowPipeText] = useState(false); // 控制管道文本显示
|
||||
const [showJunctionTextLayer, setShowJunctionTextLayer] = useState(true); // 控制节点文本图层显示
|
||||
const [showPipeTextLayer, setShowPipeTextLayer] = useState(true); // 控制管道文本图层显示
|
||||
const [showContourLayer, setShowContourLayer] = useState(true); // 控制等高线图层显示
|
||||
const [junctionText, setJunctionText] = useState("pressure");
|
||||
const [pipeText, setPipeText] = useState("flow");
|
||||
const flowAnimation = useRef(false); // 添加动画控制标志
|
||||
const waterflowUserVisible = useRef<boolean>(true); // 用户设置的水流图层可见性
|
||||
const [currentZoom, setCurrentZoom] = useState(11); // 当前缩放级别
|
||||
|
||||
// 防抖更新函数
|
||||
@@ -571,6 +572,7 @@ const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
|
||||
controls: [],
|
||||
});
|
||||
setMap(map);
|
||||
|
||||
// 恢复上次视图;如果没有则适配 MAP_EXTENT
|
||||
try {
|
||||
const stored = localStorage.getItem(MAP_VIEW_STORAGE_KEY);
|
||||
@@ -650,37 +652,13 @@ const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
|
||||
layers: [],
|
||||
});
|
||||
deckRef.current = deck;
|
||||
const deckLayer = new DeckLayer(deck);
|
||||
// deckLayer.setZIndex(1000); // 确保在最上层
|
||||
const deckLayer = new DeckLayer(deck, {
|
||||
name: "deckLayer",
|
||||
value: "deckLayer",
|
||||
});
|
||||
deckLayerRef.current = deckLayer;
|
||||
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, {
|
||||
name: "水流动画",
|
||||
value: "waterflow",
|
||||
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);
|
||||
@@ -688,85 +666,119 @@ const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
|
||||
map.setTarget(undefined);
|
||||
map.dispose();
|
||||
deck.finalize();
|
||||
deckFlow.finalize();
|
||||
};
|
||||
}, []);
|
||||
|
||||
// 当数据变化时,更新 deck.gl 图层
|
||||
useEffect(() => {
|
||||
const deck = deckRef.current;
|
||||
if (!deck) return; // 如果 deck 实例还未创建,则退出
|
||||
const newLayers = [
|
||||
new TextLayer({
|
||||
id: "junctionTextLayer",
|
||||
zIndex: 10,
|
||||
data: showJunctionText ? junctionData : [],
|
||||
getPosition: (d: any) => d.position,
|
||||
fontFamily: "Monaco, monospace",
|
||||
getText: (d: any) =>
|
||||
d[junctionText] ? (d[junctionText] as number).toFixed(3) : "",
|
||||
getSize: 18,
|
||||
fontWeight: "bold",
|
||||
getColor: [0, 0, 0],
|
||||
getAngle: 0,
|
||||
getTextAnchor: "middle",
|
||||
getAlignmentBaseline: "center",
|
||||
getPixelOffset: [0, -10],
|
||||
visible:
|
||||
showJunctionTextLayer && currentZoom >= 15 && currentZoom <= 24,
|
||||
extensions: [new CollisionFilterExtension()],
|
||||
collisionTestProps: {
|
||||
sizeScale: 3, // 增加碰撞检测的尺寸以提供更大间距
|
||||
},
|
||||
// 可读性设置
|
||||
characterSet: "auto",
|
||||
fontSettings: {
|
||||
sdf: true,
|
||||
fontSize: 64,
|
||||
buffer: 6,
|
||||
},
|
||||
// outlineWidth: 10,
|
||||
// outlineColor: [242, 244, 246, 255],
|
||||
}),
|
||||
new TextLayer({
|
||||
id: "pipeTextLayer",
|
||||
zIndex: 10,
|
||||
data: showPipeText ? pipeData : [],
|
||||
getPosition: (d: any) => d.position,
|
||||
fontFamily: "Monaco, monospace",
|
||||
getText: (d: any) =>
|
||||
d[pipeText] ? Math.abs(d[pipeText] as number).toFixed(3) : "",
|
||||
getSize: 18,
|
||||
fontWeight: "bold",
|
||||
getColor: [0, 0, 0],
|
||||
getAngle: (d: any) => d.angle || 0,
|
||||
getPixelOffset: [0, -8],
|
||||
getTextAnchor: "middle",
|
||||
getAlignmentBaseline: "bottom",
|
||||
visible: showPipeTextLayer && currentZoom >= 15 && currentZoom <= 24,
|
||||
extensions: [new CollisionFilterExtension()],
|
||||
collisionTestProps: {
|
||||
sizeScale: 3, // 增加碰撞检测的尺寸以提供更大间距
|
||||
},
|
||||
// 可读性设置
|
||||
characterSet: "auto",
|
||||
fontSettings: {
|
||||
sdf: true,
|
||||
fontSize: 64,
|
||||
buffer: 6,
|
||||
},
|
||||
// outlineWidth: 10,
|
||||
// outlineColor: [242, 244, 246, 255],
|
||||
}),
|
||||
];
|
||||
deck.setProps({ layers: newLayers });
|
||||
const deckLayer = deckLayerRef.current;
|
||||
if (!deckLayer) return; // 如果 deck 实例还未创建,则退出
|
||||
if (!junctionData.length) return;
|
||||
if (!pipeData.length) return;
|
||||
console.log(pipeData);
|
||||
console.log(pipeText);
|
||||
const junctionTextLayer = new TextLayer({
|
||||
id: "junctionTextLayer",
|
||||
zIndex: 10,
|
||||
data: showJunctionText ? junctionData : [],
|
||||
getPosition: (d: any) => d.position,
|
||||
fontFamily: "Monaco, monospace",
|
||||
getText: (d: any) =>
|
||||
d[junctionText] ? (d[junctionText] as number).toFixed(3) : "",
|
||||
getSize: 18,
|
||||
fontWeight: "bold",
|
||||
getColor: [0, 0, 0],
|
||||
getAngle: 0,
|
||||
getTextAnchor: "middle",
|
||||
getAlignmentBaseline: "center",
|
||||
getPixelOffset: [0, -10],
|
||||
visible: showJunctionTextLayer && currentZoom >= 15 && currentZoom <= 24,
|
||||
extensions: [new CollisionFilterExtension()],
|
||||
collisionTestProps: {
|
||||
sizeScale: 3, // 增加碰撞检测的尺寸以提供更大间距
|
||||
},
|
||||
// 可读性设置
|
||||
characterSet: "auto",
|
||||
fontSettings: {
|
||||
sdf: true,
|
||||
fontSize: 64,
|
||||
buffer: 6,
|
||||
},
|
||||
// outlineWidth: 10,
|
||||
// outlineColor: [242, 244, 246, 255],
|
||||
});
|
||||
const pipeTextLayer = new TextLayer({
|
||||
id: "pipeTextLayer",
|
||||
zIndex: 10,
|
||||
data: showPipeText ? pipeData : [],
|
||||
getPosition: (d: any) => d.position,
|
||||
fontFamily: "Monaco, monospace",
|
||||
getText: (d: any) =>
|
||||
d[pipeText] ? Math.abs(d[pipeText] as number).toFixed(3) : "",
|
||||
getSize: 18,
|
||||
fontWeight: "bold",
|
||||
getColor: [0, 0, 0],
|
||||
getAngle: (d: any) => d.angle || 0,
|
||||
getPixelOffset: [0, -8],
|
||||
getTextAnchor: "middle",
|
||||
getAlignmentBaseline: "bottom",
|
||||
visible: showPipeTextLayer && currentZoom >= 15 && currentZoom <= 24,
|
||||
extensions: [new CollisionFilterExtension()],
|
||||
collisionTestProps: {
|
||||
sizeScale: 3, // 增加碰撞检测的尺寸以提供更大间距
|
||||
},
|
||||
// 可读性设置
|
||||
characterSet: "auto",
|
||||
fontSettings: {
|
||||
sdf: true,
|
||||
fontSize: 64,
|
||||
buffer: 6,
|
||||
},
|
||||
// outlineWidth: 10,
|
||||
// outlineColor: [242, 244, 246, 255],
|
||||
});
|
||||
if (deckLayer.getDeckLayerById("junctionTextLayer")) {
|
||||
// 传入完整 layer 实例以保证 clone/替换时保留 layer 类型和方法
|
||||
deckLayer.updateDeckLayer("junctionTextLayer", junctionTextLayer);
|
||||
} else {
|
||||
deckLayer.addDeckLayer(junctionTextLayer);
|
||||
}
|
||||
if (deckLayer.getDeckLayerById("pipeTextLayer")) {
|
||||
deckLayer.updateDeckLayer("pipeTextLayer", pipeTextLayer);
|
||||
} else {
|
||||
deckLayer.addDeckLayer(pipeTextLayer);
|
||||
}
|
||||
console.log(deckLayer.getDeckLayers());
|
||||
}, [
|
||||
junctionData,
|
||||
pipeData,
|
||||
currentZoom,
|
||||
showJunctionText,
|
||||
showPipeText,
|
||||
showJunctionTextLayer,
|
||||
showPipeTextLayer,
|
||||
showContourLayer,
|
||||
junctionText,
|
||||
pipeText,
|
||||
]);
|
||||
// 控制流动动画开关
|
||||
useEffect(() => {
|
||||
if (pipeText === "flow" && currentPipeCalData.length > 0) {
|
||||
flowAnimation.current = true;
|
||||
} else {
|
||||
flowAnimation.current = false;
|
||||
}
|
||||
const deckLayer = deckLayerRef.current;
|
||||
if (!deckLayer) return; // 如果 deck 实例还未创建,则退出
|
||||
|
||||
let animationFrameId: number; // 保存 requestAnimationFrame 的 ID
|
||||
|
||||
// 动画循环
|
||||
const animate = () => {
|
||||
if (!deck || !flowAnimation.current) return; // 添加检查,防止空数据或停止旧循环
|
||||
if (!deckRef.current || !flowAnimation.current) return; // 添加检查,防止空数据或停止旧循环
|
||||
// 动画总时长(秒)
|
||||
if (pipeData.length === 0) {
|
||||
requestAnimationFrame(animate);
|
||||
animationFrameId = requestAnimationFrame(animate);
|
||||
return;
|
||||
}
|
||||
const animationDuration = 10;
|
||||
@@ -787,119 +799,31 @@ const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
|
||||
getColor: [0, 220, 255],
|
||||
opacity: 0.8,
|
||||
visible:
|
||||
waterflowUserVisible.current &&
|
||||
flowAnimation.current &&
|
||||
currentZoom >= 12 &&
|
||||
currentZoom <= 24,
|
||||
flowAnimation.current && currentZoom >= 12 && currentZoom <= 24,
|
||||
widthMinPixels: 5,
|
||||
jointRounded: true, // 拐角变圆
|
||||
// capRounded: true, // 端点变圆
|
||||
trailLength: 2, // 水流尾迹淡出时间
|
||||
currentTime: currentTime,
|
||||
});
|
||||
|
||||
// 获取当前除 waterflowLayer 之外的所有图层
|
||||
const otherLayers = deck.props.layers.filter(
|
||||
(layer: any) => layer && layer.id !== "waterflowLayer"
|
||||
);
|
||||
|
||||
deck.setProps({
|
||||
layers: [...otherLayers, waterflowLayer],
|
||||
});
|
||||
|
||||
if (deckLayer.getDeckLayerById("waterflowLayer")) {
|
||||
deckLayer.updateDeckLayer("waterflowLayer", waterflowLayer);
|
||||
} else {
|
||||
deckLayer.addDeckLayer(waterflowLayer);
|
||||
}
|
||||
// 继续请求动画帧,每帧执行一次函数
|
||||
requestAnimationFrame(animate);
|
||||
};
|
||||
animate();
|
||||
}, [
|
||||
flowAnimation,
|
||||
junctionData,
|
||||
pipeData,
|
||||
currentZoom,
|
||||
showJunctionText,
|
||||
showPipeText,
|
||||
showJunctionTextLayer,
|
||||
showPipeTextLayer,
|
||||
junctionText,
|
||||
pipeText,
|
||||
]);
|
||||
// 控制流动动画开关
|
||||
useEffect(() => {
|
||||
if (pipeText === "flow" && currentPipeCalData.length > 0) {
|
||||
flowAnimation.current = true;
|
||||
} else {
|
||||
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);
|
||||
animationFrameId = requestAnimationFrame(animate);
|
||||
};
|
||||
animate();
|
||||
|
||||
// 清理函数
|
||||
// 清理函数:取消动画帧
|
||||
return () => {
|
||||
if (animationId) {
|
||||
cancelAnimationFrame(animationId);
|
||||
}
|
||||
if (deckFlow) {
|
||||
deckFlow.setProps({ layers: [] });
|
||||
if (animationFrameId) {
|
||||
cancelAnimationFrame(animationFrameId);
|
||||
}
|
||||
};
|
||||
}, [flowAnimation, pipeData, currentZoom]);
|
||||
}, [currentZoom, currentPipeCalData, pipeText, pipeData.length]);
|
||||
|
||||
// 计算值更新时,更新 junctionData 和 pipeData
|
||||
useEffect(() => {
|
||||
const junctionProperties = junctionText;
|
||||
@@ -965,6 +889,7 @@ const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
|
||||
setCurrentPipeCalData,
|
||||
setShowJunctionText,
|
||||
setShowPipeText,
|
||||
setShowContourLayer,
|
||||
setJunctionText,
|
||||
setPipeText,
|
||||
showJunctionText,
|
||||
@@ -980,7 +905,6 @@ const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
|
||||
{children}
|
||||
</div>
|
||||
<canvas id="deck-canvas" />
|
||||
<canvas id="deck-flow-canvas" />
|
||||
</MapContext.Provider>
|
||||
</DataContext.Provider>
|
||||
</>
|
||||
|
||||
Reference in New Issue
Block a user