完成时间轴前后端数据连通
This commit is contained in:
@@ -24,7 +24,24 @@ 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 { tr } from "date-fns/locale";
|
||||
|
||||
interface MapComponentProps {
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
interface DataContextType {
|
||||
junctionData: any[];
|
||||
pipeData: any[];
|
||||
setJunctionDataState: React.Dispatch<React.SetStateAction<any[]>>;
|
||||
setPipeDataState: React.Dispatch<React.SetStateAction<any[]>>;
|
||||
showJunctionText?: boolean; // 是否显示节点文本
|
||||
showPipeText?: boolean; // 是否显示管道文本
|
||||
setShowJunctionText?: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
setShowPipeText?: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
junctionText: string;
|
||||
pipeText: string;
|
||||
setJunctionText?: React.Dispatch<React.SetStateAction<string>>;
|
||||
setPipeText?: React.Dispatch<React.SetStateAction<string>>;
|
||||
}
|
||||
|
||||
// 创建自定义Layer类来包装deck.gl
|
||||
class DeckLayer extends Layer {
|
||||
@@ -50,8 +67,9 @@ class DeckLayer extends Layer {
|
||||
}
|
||||
// 跨组件传递
|
||||
const MapContext = createContext<OlMap | undefined>(undefined);
|
||||
const DataContext = createContext<DataContextType | undefined>(undefined);
|
||||
|
||||
const extent = config.mapExtent;
|
||||
const backendUrl = config.backendUrl;
|
||||
const mapUrl = config.mapUrl;
|
||||
|
||||
// 添加防抖函数
|
||||
@@ -69,16 +87,15 @@ function debounce<F extends (...args: any[]) => any>(func: F, waitFor: number) {
|
||||
export const useMap = () => {
|
||||
return useContext(MapContext);
|
||||
};
|
||||
export const useData = () => {
|
||||
return useContext(DataContext);
|
||||
};
|
||||
|
||||
const MapComponent: React.FC = () => {
|
||||
const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
|
||||
const mapRef = useRef<HTMLDivElement | null>(null);
|
||||
const deckRef = useRef<Deck | null>(null);
|
||||
|
||||
const [map, setMap] = useState<OlMap>();
|
||||
const [currentTime, setCurrentTime] = useState(
|
||||
new Date("2025-09-17T00:30:00+08:00")
|
||||
);
|
||||
const intervalRef = useRef<NodeJS.Timeout | null>(null);
|
||||
const [junctionData, setJunctionDataState] = useState<any[]>([]);
|
||||
const [pipeData, setPipeDataState] = useState<any[]>([]);
|
||||
const junctionDataIds = useRef(new Set<string>());
|
||||
@@ -86,12 +103,11 @@ const MapComponent: React.FC = () => {
|
||||
const tileJunctionDataBuffer = useRef<any[]>([]);
|
||||
const tilePipeDataBuffer = useRef<any[]>([]);
|
||||
|
||||
let showJunctionText = true; // 控制节点文本显示
|
||||
let showPipeText = true; // 控制管道文本显示
|
||||
let junctionText = "pressure";
|
||||
let pipeText = "flow";
|
||||
let animate = false; // 控制是否动画
|
||||
const isAnimating = useRef(false); // 添加动画控制标志
|
||||
const [showJunctionText, setShowJunctionText] = useState(false); // 控制节点文本显示
|
||||
const [showPipeText, setShowPipeText] = useState(false); // 控制管道文本显示
|
||||
const [junctionText, setJunctionText] = useState("");
|
||||
const [pipeText, setPipeText] = useState("");
|
||||
const flowAnimation = useRef(true); // 添加动画控制标志
|
||||
const [currentZoom, setCurrentZoom] = useState(12); // 当前缩放级别
|
||||
// 防抖更新函数
|
||||
const debouncedUpdateData = useRef(
|
||||
@@ -134,80 +150,6 @@ const MapComponent: React.FC = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const setFrameData = async (queryTime: Date) => {
|
||||
const query_time = queryTime.toISOString();
|
||||
console.log("Query Time:", query_time);
|
||||
try {
|
||||
// 定义需要查询的属性
|
||||
const junctionProperties = junctionText;
|
||||
const pipeProperties = pipeText;
|
||||
// 同时查询节点和管道数据
|
||||
const starttime = Date.now();
|
||||
const [nodeResponse, linkResponse] = await Promise.all([
|
||||
fetch(
|
||||
`${backendUrl}/queryallrecordsbytimeproperty/?querytime=${query_time}&type=node&property=${junctionProperties}`
|
||||
),
|
||||
fetch(
|
||||
`${backendUrl}/queryallrecordsbytimeproperty/?querytime=${query_time}&type=link&property=${pipeProperties}`
|
||||
),
|
||||
]);
|
||||
|
||||
const nodeRecords = await nodeResponse.json();
|
||||
const linkRecords = await linkResponse.json();
|
||||
// 将 nodeRecords 转换为 Map 以提高查找效率
|
||||
const nodeMap: Map<string, any> = new Map(
|
||||
nodeRecords.results.map((r: any) => [r.ID, r])
|
||||
);
|
||||
// 将 linkRecords 转换为 Map 以提高查找效率
|
||||
const linkMap: Map<string, any> = new Map(
|
||||
linkRecords.results.map((r: any) => [r.ID, r])
|
||||
);
|
||||
|
||||
// 更新junctionData
|
||||
setJunctionDataState((prev) =>
|
||||
prev.map((j) => {
|
||||
const record = nodeMap.get(j.id);
|
||||
if (record) {
|
||||
return {
|
||||
...j,
|
||||
[junctionProperties]: record.value,
|
||||
};
|
||||
}
|
||||
return j;
|
||||
})
|
||||
);
|
||||
|
||||
// 更新pipeData
|
||||
setPipeDataState((prev) =>
|
||||
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;
|
||||
})
|
||||
);
|
||||
// 属性为 flow 时启动动画
|
||||
if (pipeProperties === "flow" && animate) {
|
||||
isAnimating.current = true;
|
||||
} else {
|
||||
isAnimating.current = false;
|
||||
}
|
||||
const endtime = Date.now();
|
||||
console.log("Data fetch and update time:", endtime - starttime, "ms");
|
||||
} catch (error) {
|
||||
console.error("Error fetching data:", error);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!mapRef.current) return;
|
||||
// 添加 MVT 瓦片加载逻辑
|
||||
@@ -361,8 +303,12 @@ const MapComponent: React.FC = () => {
|
||||
value: "junctions",
|
||||
type: "point",
|
||||
properties: [
|
||||
{ name: "需求量", value: "demand" },
|
||||
{ name: "海拔高度", value: "elevation" },
|
||||
// { name: "需求量", value: "demand" },
|
||||
// { name: "海拔高度", value: "elevation" },
|
||||
{ name: "实际需求量", value: "actualdemand" },
|
||||
{ name: "水头", value: "head" },
|
||||
{ name: "压力", value: "pressure" },
|
||||
{ name: "水质", value: "quality" },
|
||||
],
|
||||
},
|
||||
});
|
||||
@@ -378,9 +324,17 @@ const MapComponent: React.FC = () => {
|
||||
value: "pipes",
|
||||
type: "linestring",
|
||||
properties: [
|
||||
{ name: "直径", value: "diameter" },
|
||||
{ name: "粗糙度", value: "roughness" },
|
||||
{ name: "局部损失", value: "minor_loss" },
|
||||
// { 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" },
|
||||
],
|
||||
},
|
||||
});
|
||||
@@ -436,7 +390,7 @@ const MapComponent: React.FC = () => {
|
||||
const newLayers = [
|
||||
new TextLayer({
|
||||
id: "junctionTextLayer",
|
||||
zIndex: 1000,
|
||||
zIndex: 10,
|
||||
data: showJunctionText ? junctionData : [],
|
||||
getPosition: (d: any) => d.position,
|
||||
fontFamily: "Monaco, monospace",
|
||||
@@ -456,7 +410,7 @@ const MapComponent: React.FC = () => {
|
||||
}),
|
||||
new TextLayer({
|
||||
id: "pipeTextLayer",
|
||||
zIndex: 1000,
|
||||
zIndex: 10,
|
||||
data: showPipeText ? pipeData : [],
|
||||
getPosition: (d: any) => d.position,
|
||||
fontFamily: "Monaco, monospace",
|
||||
@@ -479,7 +433,7 @@ const MapComponent: React.FC = () => {
|
||||
|
||||
// 动画循环
|
||||
const animate = () => {
|
||||
if (!deck || !isAnimating.current) return; // 添加检查,防止空数据或停止旧循环
|
||||
if (!deck || !flowAnimation.current) return; // 添加检查,防止空数据或停止旧循环
|
||||
// 动画总时长(秒)
|
||||
if (pipeData.length === 0) {
|
||||
requestAnimationFrame(animate);
|
||||
@@ -496,7 +450,7 @@ const MapComponent: React.FC = () => {
|
||||
const waterflowLayer = new TripsLayer({
|
||||
id: "waterflowLayer",
|
||||
data: pipeData,
|
||||
getPath: (d) => (isAnimating.current ? d.path : []),
|
||||
getPath: (d) => (flowAnimation.current ? d.path : []),
|
||||
getTimestamps: (d) => {
|
||||
return d.timestamps; // 这些应该是与 currentTime 匹配的数值
|
||||
},
|
||||
@@ -522,35 +476,31 @@ const MapComponent: React.FC = () => {
|
||||
requestAnimationFrame(animate);
|
||||
};
|
||||
animate();
|
||||
}, [isAnimating, junctionData, pipeData]);
|
||||
|
||||
// 启动时间更新interval
|
||||
useEffect(() => {
|
||||
intervalRef.current = setInterval(() => {
|
||||
setCurrentTime((prev) => new Date(prev.getTime() + 1800 * 1000));
|
||||
}, 10 * 1000);
|
||||
return () => {
|
||||
if (intervalRef.current) clearInterval(intervalRef.current);
|
||||
};
|
||||
}, []);
|
||||
|
||||
// 当currentTime改变时,获取数据
|
||||
useEffect(() => {
|
||||
const fetchData = async () => {
|
||||
await setFrameData(currentTime);
|
||||
};
|
||||
fetchData();
|
||||
}, [currentTime]);
|
||||
}, [flowAnimation, junctionData, pipeData]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<MapContext.Provider value={map}>
|
||||
<div className="relative w-full h-full">
|
||||
<div ref={mapRef} className="w-full h-full"></div>
|
||||
<MapTools />
|
||||
</div>
|
||||
<canvas id="deck-canvas" />
|
||||
</MapContext.Provider>
|
||||
<DataContext.Provider
|
||||
value={{
|
||||
junctionData,
|
||||
pipeData,
|
||||
setJunctionDataState,
|
||||
setPipeDataState,
|
||||
showJunctionText,
|
||||
showPipeText,
|
||||
junctionText,
|
||||
pipeText,
|
||||
}}
|
||||
>
|
||||
<MapContext.Provider value={map}>
|
||||
<div className="relative w-full h-full">
|
||||
<div ref={mapRef} className="w-full h-full"></div>
|
||||
<MapTools />
|
||||
{children}
|
||||
</div>
|
||||
<canvas id="deck-canvas" />
|
||||
</MapContext.Provider>
|
||||
</DataContext.Provider>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user