属性查询面板添加计算值;完善时间轴获取数据的缓存机制;
This commit is contained in:
@@ -28,6 +28,7 @@ import { FlatStyleLike } from "ol/style/flat";
|
|||||||
import { calculateClassification } from "@utils/breaks_classification";
|
import { calculateClassification } from "@utils/breaks_classification";
|
||||||
import { parseColor } from "@utils/parseColor";
|
import { parseColor } from "@utils/parseColor";
|
||||||
import { VectorTile } from "ol";
|
import { VectorTile } from "ol";
|
||||||
|
import { useNotification } from "@refinedev/core";
|
||||||
|
|
||||||
interface StyleConfig {
|
interface StyleConfig {
|
||||||
property: string;
|
property: string;
|
||||||
@@ -117,6 +118,8 @@ const StyleEditorPanel: React.FC = () => {
|
|||||||
setPipeText,
|
setPipeText,
|
||||||
} = data;
|
} = data;
|
||||||
|
|
||||||
|
const { open, close } = useNotification();
|
||||||
|
|
||||||
const [applyJunctionStyle, setApplyJunctionStyle] = useState(false);
|
const [applyJunctionStyle, setApplyJunctionStyle] = useState(false);
|
||||||
const [applyPipeStyle, setApplyPipeStyle] = useState(false);
|
const [applyPipeStyle, setApplyPipeStyle] = useState(false);
|
||||||
const [styleUpdateTrigger, setStyleUpdateTrigger] = useState(0); // 用于触发样式更新的状态
|
const [styleUpdateTrigger, setStyleUpdateTrigger] = useState(0); // 用于触发样式更新的状态
|
||||||
@@ -194,7 +197,7 @@ const StyleEditorPanel: React.FC = () => {
|
|||||||
const finalLegendConfig: LegendStyleConfig = legendConfig || {
|
const finalLegendConfig: LegendStyleConfig = legendConfig || {
|
||||||
layerId,
|
layerId,
|
||||||
layerName,
|
layerName,
|
||||||
property: styleConfig.property,
|
property: selectedProperty.name,
|
||||||
colors: [],
|
colors: [],
|
||||||
type: "point",
|
type: "point",
|
||||||
dimensions: [],
|
dimensions: [],
|
||||||
@@ -240,15 +243,22 @@ const StyleEditorPanel: React.FC = () => {
|
|||||||
setShowJunctionText(styleConfig.showLabels);
|
setShowJunctionText(styleConfig.showLabels);
|
||||||
setApplyJunctionStyle(true);
|
setApplyJunctionStyle(true);
|
||||||
saveLayerStyle(layerId);
|
saveLayerStyle(layerId);
|
||||||
|
open?.({
|
||||||
|
type: "success",
|
||||||
|
message: "节点图层样式设置成功,等待数据更新。",
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (layerId === "pipes") {
|
if (layerId === "pipes") {
|
||||||
console.log(styleConfig);
|
|
||||||
if (setPipeText && setShowPipeText) {
|
if (setPipeText && setShowPipeText) {
|
||||||
setPipeText(property);
|
setPipeText(property);
|
||||||
setShowPipeText(styleConfig.showLabels);
|
setShowPipeText(styleConfig.showLabels);
|
||||||
setApplyPipeStyle(true);
|
setApplyPipeStyle(true);
|
||||||
saveLayerStyle(layerId);
|
saveLayerStyle(layerId);
|
||||||
|
open?.({
|
||||||
|
type: "success",
|
||||||
|
message: "管道图层样式设置成功,等待数据更新。",
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 触发样式更新
|
// 触发样式更新
|
||||||
|
|||||||
@@ -33,16 +33,25 @@ const Timeline: React.FC = () => {
|
|||||||
return <div>Loading...</div>; // 或其他占位符
|
return <div>Loading...</div>; // 或其他占位符
|
||||||
}
|
}
|
||||||
const {
|
const {
|
||||||
|
currentTime,
|
||||||
|
setCurrentTime,
|
||||||
|
selectedDate,
|
||||||
|
setSelectedDate,
|
||||||
setCurrentJunctionCalData,
|
setCurrentJunctionCalData,
|
||||||
setCurrentPipeCalData,
|
setCurrentPipeCalData,
|
||||||
junctionText,
|
junctionText,
|
||||||
pipeText,
|
pipeText,
|
||||||
} = data;
|
} = data;
|
||||||
|
if (
|
||||||
|
setCurrentTime === undefined ||
|
||||||
|
currentTime === undefined ||
|
||||||
|
selectedDate === undefined ||
|
||||||
|
setSelectedDate === undefined
|
||||||
|
) {
|
||||||
|
return <div>Loading...</div>; // 或其他占位符
|
||||||
|
}
|
||||||
const { open, close } = useNotification();
|
const { open, close } = useNotification();
|
||||||
|
|
||||||
const [currentTime, setCurrentTime] = useState<number>(0); // 分钟数 (0-1439)
|
|
||||||
const [selectedDate, setSelectedDate] = useState<Date>(new Date("2025-9-17"));
|
|
||||||
// const [selectedDate, setSelectedDate] = useState<Date>(new Date()); // 默认今天
|
|
||||||
const [isPlaying, setIsPlaying] = useState<boolean>(false);
|
const [isPlaying, setIsPlaying] = useState<boolean>(false);
|
||||||
const [playInterval, setPlayInterval] = useState<number>(5000); // 毫秒
|
const [playInterval, setPlayInterval] = useState<number>(5000); // 毫秒
|
||||||
const [calculatedInterval, setCalculatedInterval] = useState<number>(1440); // 分钟
|
const [calculatedInterval, setCalculatedInterval] = useState<number>(1440); // 分钟
|
||||||
@@ -51,62 +60,79 @@ const Timeline: React.FC = () => {
|
|||||||
const intervalRef = useRef<NodeJS.Timeout | null>(null);
|
const intervalRef = useRef<NodeJS.Timeout | null>(null);
|
||||||
const timelineRef = useRef<HTMLDivElement>(null);
|
const timelineRef = useRef<HTMLDivElement>(null);
|
||||||
// 添加缓存引用
|
// 添加缓存引用
|
||||||
const cacheRef = useRef<
|
const nodeCacheRef = useRef<Map<string, any[]>>(new Map());
|
||||||
Map<string, { nodeRecords: any[]; linkRecords: any[] }>
|
const linkCacheRef = useRef<Map<string, any[]>>(new Map());
|
||||||
>(new Map());
|
|
||||||
// 添加防抖引用
|
// 添加防抖引用
|
||||||
const debounceRef = useRef<NodeJS.Timeout | null>(null);
|
const debounceRef = useRef<NodeJS.Timeout | null>(null);
|
||||||
|
|
||||||
const fetchFrameData = async (queryTime: Date) => {
|
const fetchFrameData = async (
|
||||||
|
queryTime: Date,
|
||||||
|
junctionProperties: string,
|
||||||
|
pipeProperties: string
|
||||||
|
) => {
|
||||||
const query_time = queryTime.toISOString();
|
const query_time = queryTime.toISOString();
|
||||||
const cacheKey = query_time;
|
let nodeRecords: any = { results: [] };
|
||||||
// console.log("Fetching data for time:", query_time);
|
let linkRecords: any = { results: [] };
|
||||||
// console.log("Junction Property:", junctionText);
|
const requests: Promise<Response>[] = [];
|
||||||
// console.log("Pipe Property:", pipeText);
|
let nodePromise: Promise<any> | null = null;
|
||||||
// 检查缓存
|
let linkPromise: Promise<any> | null = null;
|
||||||
if (cacheRef.current.has(cacheKey)) {
|
// 检查node缓存
|
||||||
const { nodeRecords, linkRecords } = cacheRef.current.get(cacheKey)!;
|
if (junctionProperties !== "") {
|
||||||
// 使用缓存数据更新状态
|
const nodeCacheKey = `${query_time}_${junctionProperties}`;
|
||||||
updateDataStates(nodeRecords, linkRecords);
|
if (nodeCacheRef.current.has(nodeCacheKey)) {
|
||||||
return;
|
nodeRecords = nodeCacheRef.current.get(nodeCacheKey)!;
|
||||||
}
|
} else {
|
||||||
|
nodePromise = fetch(
|
||||||
try {
|
|
||||||
// 定义需要查询的属性
|
|
||||||
const junctionProperties = junctionText;
|
|
||||||
const pipeProperties = pipeText;
|
|
||||||
// 如果属性未定义或为空,直接返回
|
|
||||||
if (junctionProperties === "" || pipeProperties === "") {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
console.log(
|
|
||||||
"Query Time:",
|
|
||||||
queryTime.toLocaleDateString() + " " + queryTime.toLocaleTimeString()
|
|
||||||
);
|
|
||||||
// 同时查询节点和管道数据
|
|
||||||
const [nodeResponse, linkResponse] = await Promise.all([
|
|
||||||
fetch(
|
|
||||||
`${backendUrl}/queryallrecordsbytimeproperty/?querytime=${query_time}&type=node&property=${junctionProperties}`
|
`${backendUrl}/queryallrecordsbytimeproperty/?querytime=${query_time}&type=node&property=${junctionProperties}`
|
||||||
),
|
);
|
||||||
fetch(
|
requests.push(nodePromise);
|
||||||
`${backendUrl}/queryallrecordsbytimeproperty/?querytime=${query_time}&type=link&property=${pipeProperties}`
|
}
|
||||||
),
|
|
||||||
]);
|
|
||||||
|
|
||||||
const nodeRecords = await nodeResponse.json();
|
|
||||||
const linkRecords = await linkResponse.json();
|
|
||||||
|
|
||||||
// 缓存数据
|
|
||||||
cacheRef.current.set(cacheKey, {
|
|
||||||
nodeRecords: nodeRecords.results,
|
|
||||||
linkRecords: linkRecords.results,
|
|
||||||
});
|
|
||||||
|
|
||||||
// 更新状态
|
|
||||||
updateDataStates(nodeRecords.results, linkRecords.results);
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error fetching data:", error);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 检查link缓存
|
||||||
|
if (pipeProperties !== "") {
|
||||||
|
const linkCacheKey = `${query_time}_${pipeProperties}`;
|
||||||
|
if (linkCacheRef.current.has(linkCacheKey)) {
|
||||||
|
linkRecords = linkCacheRef.current.get(linkCacheKey)!;
|
||||||
|
} else {
|
||||||
|
linkPromise = fetch(
|
||||||
|
`${backendUrl}/queryallrecordsbytimeproperty/?querytime=${query_time}&type=link&property=${pipeProperties}`
|
||||||
|
);
|
||||||
|
requests.push(linkPromise);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
"Query Time:",
|
||||||
|
queryTime.toLocaleDateString() + " " + queryTime.toLocaleTimeString()
|
||||||
|
);
|
||||||
|
// 等待所有有效请求
|
||||||
|
const responses = await Promise.all(requests);
|
||||||
|
|
||||||
|
if (nodePromise) {
|
||||||
|
const nodeResponse = responses.shift()!;
|
||||||
|
if (!nodeResponse.ok)
|
||||||
|
throw new Error(`Node fetch failed: ${nodeResponse.status}`);
|
||||||
|
nodeRecords = await nodeResponse.json();
|
||||||
|
// 缓存数据
|
||||||
|
nodeCacheRef.current.set(
|
||||||
|
`${query_time}_${junctionProperties}`,
|
||||||
|
nodeRecords || []
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (linkPromise) {
|
||||||
|
const linkResponse = responses.shift()!;
|
||||||
|
if (!linkResponse.ok)
|
||||||
|
throw new Error(`Link fetch failed: ${linkResponse.status}`);
|
||||||
|
linkRecords = await linkResponse.json();
|
||||||
|
// 缓存数据
|
||||||
|
linkCacheRef.current.set(
|
||||||
|
`${query_time}_${pipeProperties}`,
|
||||||
|
linkRecords || []
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// 更新状态
|
||||||
|
updateDataStates(nodeRecords.results || [], linkRecords.results || []);
|
||||||
};
|
};
|
||||||
|
|
||||||
// 提取更新状态的逻辑
|
// 提取更新状态的逻辑
|
||||||
@@ -181,10 +207,10 @@ const Timeline: React.FC = () => {
|
|||||||
// 播放控制
|
// 播放控制
|
||||||
const handlePlay = useCallback(() => {
|
const handlePlay = useCallback(() => {
|
||||||
if (!isPlaying) {
|
if (!isPlaying) {
|
||||||
if (junctionText === "" || pipeText === "") {
|
if (junctionText === "" && pipeText === "") {
|
||||||
open?.({
|
open?.({
|
||||||
type: "error",
|
type: "error",
|
||||||
message: "请先设置节点和管道的属性。",
|
message: "请至少设定并应用一个图层的样式。",
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -270,8 +296,25 @@ const Timeline: React.FC = () => {
|
|||||||
|
|
||||||
// 添加 useEffect 来监听 currentTime 和 selectedDate 的变化,并获取数据
|
// 添加 useEffect 来监听 currentTime 和 selectedDate 的变化,并获取数据
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchFrameData(currentTimeToDate(selectedDate, currentTime));
|
// 首次加载时,如果 selectedDate 或 currentTime 未定义,则跳过执行,避免报错
|
||||||
}, [currentTime, selectedDate]);
|
if (selectedDate && currentTime !== undefined) {
|
||||||
|
// 检查至少一个属性有值
|
||||||
|
const junctionProperties = junctionText;
|
||||||
|
const pipeProperties = pipeText;
|
||||||
|
if (junctionProperties === "" && pipeProperties === "") {
|
||||||
|
open?.({
|
||||||
|
type: "error",
|
||||||
|
message: "请至少设定并应用一个图层的样式。",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fetchFrameData(
|
||||||
|
currentTimeToDate(selectedDate, currentTime),
|
||||||
|
junctionText,
|
||||||
|
pipeText
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}, [junctionText, pipeText, currentTime, selectedDate]);
|
||||||
|
|
||||||
// 组件卸载时清理定时器和防抖
|
// 组件卸载时清理定时器和防抖
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React, { useState, useEffect, useCallback } from "react";
|
import React, { useState, useEffect, useCallback } from "react";
|
||||||
import { useMap } from "../MapComponent";
|
import { useData, useMap } from "../MapComponent";
|
||||||
import ToolbarButton from "@/components/olmap/common/ToolbarButton";
|
import ToolbarButton from "@/components/olmap/common/ToolbarButton";
|
||||||
import InfoOutlinedIcon from "@mui/icons-material/InfoOutlined";
|
import InfoOutlinedIcon from "@mui/icons-material/InfoOutlined";
|
||||||
import EditOutlinedIcon from "@mui/icons-material/EditOutlined";
|
import EditOutlinedIcon from "@mui/icons-material/EditOutlined";
|
||||||
@@ -23,8 +23,14 @@ import { toLonLat } from "ol/proj";
|
|||||||
import { booleanIntersects, buffer, point, toWgs84 } from "@turf/turf";
|
import { booleanIntersects, buffer, point, toWgs84 } from "@turf/turf";
|
||||||
import RenderFeature from "ol/render/Feature";
|
import RenderFeature from "ol/render/Feature";
|
||||||
|
|
||||||
|
import { config } from "@/config/config";
|
||||||
|
const backendUrl = config.backendUrl;
|
||||||
|
|
||||||
const Toolbar: React.FC = () => {
|
const Toolbar: React.FC = () => {
|
||||||
const map = useMap();
|
const map = useMap();
|
||||||
|
const data = useData();
|
||||||
|
if (!data) return null;
|
||||||
|
const { currentTime, selectedDate } = data;
|
||||||
const [activeTools, setActiveTools] = useState<string[]>([]);
|
const [activeTools, setActiveTools] = useState<string[]>([]);
|
||||||
const [highlightFeature, setHighlightFeature] = useState<FeatureLike | null>(
|
const [highlightFeature, setHighlightFeature] = useState<FeatureLike | null>(
|
||||||
null
|
null
|
||||||
@@ -186,7 +192,7 @@ const Toolbar: React.FC = () => {
|
|||||||
const features = results
|
const features = results
|
||||||
.filter((json) => json !== null) // 过滤掉失败的请求
|
.filter((json) => json !== null) // 过滤掉失败的请求
|
||||||
.flatMap((json) => new GeoJSON().readFeatures(json));
|
.flatMap((json) => new GeoJSON().readFeatures(json));
|
||||||
console.log("查询到的要素:", features);
|
// console.log("查询到的要素:", features);
|
||||||
return features;
|
return features;
|
||||||
} else {
|
} else {
|
||||||
// 查询指定图层
|
// 查询指定图层
|
||||||
@@ -201,7 +207,7 @@ const Toolbar: React.FC = () => {
|
|||||||
}
|
}
|
||||||
const json = await response.json();
|
const json = await response.json();
|
||||||
const features = new GeoJSON().readFeatures(json);
|
const features = new GeoJSON().readFeatures(json);
|
||||||
console.log("查询到的要素:", features);
|
// console.log("查询到的要素:", features);
|
||||||
return features;
|
return features;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -399,45 +405,145 @@ const Toolbar: React.FC = () => {
|
|||||||
setShowDrawPanel(false);
|
setShowDrawPanel(false);
|
||||||
// 样式编辑器保持其当前状态,不自动关闭
|
// 样式编辑器保持其当前状态,不自动关闭
|
||||||
};
|
};
|
||||||
|
const [computedProperties, setComputedProperties] = useState<
|
||||||
|
Record<string, any>
|
||||||
|
>({});
|
||||||
|
// 添加 useEffect 来查询计算属性
|
||||||
|
useEffect(() => {
|
||||||
|
if (!highlightFeature || !selectedDate) {
|
||||||
|
setComputedProperties({});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const id = highlightFeature.getProperties().id;
|
||||||
|
if (!id) {
|
||||||
|
setComputedProperties({});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const queryComputedProperties = async () => {
|
||||||
|
try {
|
||||||
|
const properties = highlightFeature?.getProperties?.() || {};
|
||||||
|
const type =
|
||||||
|
properties.geometry?.getType?.() === "LineString" ? "link" : "node";
|
||||||
|
// selectedDate 格式化为 YYYY-MM-DD
|
||||||
|
let dateObj: Date;
|
||||||
|
if (selectedDate instanceof Date) {
|
||||||
|
dateObj = new Date(selectedDate);
|
||||||
|
} else {
|
||||||
|
dateObj = new Date(selectedDate);
|
||||||
|
}
|
||||||
|
const minutes = Number(currentTime) || 0;
|
||||||
|
dateObj.setHours(Math.floor(minutes / 60), minutes % 60, 0, 0);
|
||||||
|
// 转为 UTC ISO 字符串
|
||||||
|
const querytime = dateObj.toISOString(); // 例如 "2025-09-16T16:30:00.000Z"
|
||||||
|
const response = await fetch(
|
||||||
|
`${backendUrl}/queryrecordsbyidtime/?id=${id}&querytime=${querytime}&type=${type}`
|
||||||
|
);
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error("API request failed");
|
||||||
|
}
|
||||||
|
const data = await response.json();
|
||||||
|
setComputedProperties(data.results[0] || {});
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error querying computed properties:", error);
|
||||||
|
setComputedProperties({});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
queryComputedProperties();
|
||||||
|
}, [highlightFeature, currentTime, selectedDate]);
|
||||||
|
|
||||||
// 从要素属性中提取属性面板需要的数据
|
// 从要素属性中提取属性面板需要的数据
|
||||||
const getFeatureProperties = useCallback(() => {
|
const getFeatureProperties = useCallback(() => {
|
||||||
if (!highlightFeature) return {};
|
if (!highlightFeature) return {};
|
||||||
|
|
||||||
const properties = highlightFeature.getProperties();
|
const properties = highlightFeature.getProperties();
|
||||||
console.log(properties, properties.geometry.type, "properties");
|
// 计算属性字段,增加 key 字段
|
||||||
|
const pipeComputedFields = [
|
||||||
|
{ key: "flow", label: "流量", unit: "m³/s" },
|
||||||
|
{ key: "friction", label: "摩阻", unit: "" },
|
||||||
|
{ key: "headloss", label: "水头损失", unit: "m" },
|
||||||
|
{ key: "quality", label: "水质", unit: "mg/L" },
|
||||||
|
{ key: "reaction", label: "反应", unit: "1/s" },
|
||||||
|
{ key: "setting", label: "设置", unit: "" },
|
||||||
|
{ key: "status", label: "状态", unit: "" },
|
||||||
|
{ key: "velocity", label: "流速", unit: "m/s" },
|
||||||
|
];
|
||||||
|
const nodeComputedFields = [
|
||||||
|
{ key: "actualdemand", label: "实际需水量", unit: "m³/s" },
|
||||||
|
{ key: "head", label: "水头", unit: "m" },
|
||||||
|
{ key: "pressure", label: "压力", unit: "kPa" },
|
||||||
|
{ key: "quality", label: "水质", unit: "mg/L" },
|
||||||
|
];
|
||||||
|
|
||||||
if (properties.geometry.getType() === "LineString") {
|
if (properties.geometry.getType() === "LineString") {
|
||||||
console.log(properties, "properties");
|
let result = {
|
||||||
return {
|
|
||||||
id: properties.id,
|
id: properties.id,
|
||||||
type: "管道",
|
type: "管道",
|
||||||
properties: [
|
properties: [
|
||||||
{ label: "起始节点ID", value: properties.node1 },
|
{ label: "起始节点ID", value: properties.node1 },
|
||||||
{ label: "终点节点ID", value: properties.node2 },
|
{ label: "终点节点ID", value: properties.node2 },
|
||||||
{ label: "长度", value: properties.length.toFixed(1), unit: "m" },
|
{ label: "长度", value: properties.length?.toFixed?.(1), unit: "m" },
|
||||||
{ label: "管径", value: properties.diameter.toFixed(1), unit: "mm" },
|
{
|
||||||
|
label: "管径",
|
||||||
|
value: properties.diameter?.toFixed?.(1),
|
||||||
|
unit: "mm",
|
||||||
|
},
|
||||||
{ label: "粗糙度", value: properties.roughness },
|
{ label: "粗糙度", value: properties.roughness },
|
||||||
{ label: "局部损失", value: properties.minor_loss },
|
{ label: "局部损失", value: properties.minor_loss },
|
||||||
{ label: "初始状态", value: "开" },
|
{ label: "初始状态", value: "开" },
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
// 追加计算属性
|
||||||
|
if (computedProperties) {
|
||||||
|
pipeComputedFields.forEach(({ key, label, unit }) => {
|
||||||
|
if (computedProperties[key] !== undefined) {
|
||||||
|
result.properties.push({
|
||||||
|
label,
|
||||||
|
value:
|
||||||
|
computedProperties[key].toFixed?.(2) || computedProperties[key],
|
||||||
|
unit,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
if (properties.geometry.getType() === "Point") {
|
if (properties.geometry.getType() === "Point") {
|
||||||
return {
|
let result = {
|
||||||
id: properties.id,
|
id: properties.id,
|
||||||
type: "节点",
|
type: "节点",
|
||||||
properties: [
|
properties: [
|
||||||
{ label: "海拔", value: properties.elevation.toFixed(1), unit: "m" },
|
{
|
||||||
|
label: "海拔",
|
||||||
|
value: properties.elevation?.toFixed?.(1),
|
||||||
|
unit: "m",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: "需求量",
|
label: "需求量",
|
||||||
value: properties.demand.toFixed(1),
|
value: properties.demand?.toFixed?.(1),
|
||||||
unit: "m³/s",
|
unit: "m³/s",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
// 追加计算属性
|
||||||
|
if (computedProperties) {
|
||||||
|
nodeComputedFields.forEach(({ key, label, unit }) => {
|
||||||
|
if (computedProperties[key] !== undefined) {
|
||||||
|
result.properties.push({
|
||||||
|
label,
|
||||||
|
value:
|
||||||
|
computedProperties[key].toFixed?.(2) || computedProperties[key],
|
||||||
|
unit,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
}, [highlightFeature]);
|
}, [highlightFeature, computedProperties]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -29,6 +29,10 @@ interface MapComponentProps {
|
|||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
}
|
}
|
||||||
interface DataContextType {
|
interface DataContextType {
|
||||||
|
currentTime?: number; // 当前时间
|
||||||
|
setCurrentTime?: React.Dispatch<React.SetStateAction<number>>;
|
||||||
|
selectedDate?: Date; // 选择的日期
|
||||||
|
setSelectedDate?: React.Dispatch<React.SetStateAction<Date>>;
|
||||||
currentJunctionCalData?: any[]; // 当前计算结果
|
currentJunctionCalData?: any[]; // 当前计算结果
|
||||||
setCurrentJunctionCalData?: React.Dispatch<React.SetStateAction<any[]>>;
|
setCurrentJunctionCalData?: React.Dispatch<React.SetStateAction<any[]>>;
|
||||||
currentPipeCalData?: any[]; // 当前计算结果
|
currentPipeCalData?: any[]; // 当前计算结果
|
||||||
@@ -97,6 +101,10 @@ const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
|
|||||||
|
|
||||||
const [map, setMap] = useState<OlMap>();
|
const [map, setMap] = useState<OlMap>();
|
||||||
// currentCalData 用于存储当前计算结果
|
// currentCalData 用于存储当前计算结果
|
||||||
|
const [currentTime, setCurrentTime] = useState<number>(0);
|
||||||
|
const [selectedDate, setSelectedDate] = useState<Date>(new Date("2025-9-17"));
|
||||||
|
// const [selectedDate, setSelectedDate] = useState<Date>(new Date()); // 默认今天
|
||||||
|
|
||||||
const [currentJunctionCalData, setCurrentJunctionCalData] = useState<any[]>(
|
const [currentJunctionCalData, setCurrentJunctionCalData] = useState<any[]>(
|
||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
@@ -113,8 +121,8 @@ const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
|
|||||||
const [showPipeText, setShowPipeText] = useState(false); // 控制管道文本显示
|
const [showPipeText, setShowPipeText] = useState(false); // 控制管道文本显示
|
||||||
const [showJunctionTextLayer, setShowJunctionTextLayer] = useState(true); // 控制节点文本图层显示
|
const [showJunctionTextLayer, setShowJunctionTextLayer] = useState(true); // 控制节点文本图层显示
|
||||||
const [showPipeTextLayer, setShowPipeTextLayer] = useState(true); // 控制管道文本图层显示
|
const [showPipeTextLayer, setShowPipeTextLayer] = useState(true); // 控制管道文本图层显示
|
||||||
const [junctionText, setJunctionText] = useState("pressure");
|
const [junctionText, setJunctionText] = useState("");
|
||||||
const [pipeText, setPipeText] = useState("flow");
|
const [pipeText, setPipeText] = useState("");
|
||||||
const flowAnimation = useRef(false); // 添加动画控制标志
|
const flowAnimation = useRef(false); // 添加动画控制标志
|
||||||
const [currentZoom, setCurrentZoom] = useState(12); // 当前缩放级别
|
const [currentZoom, setCurrentZoom] = useState(12); // 当前缩放级别
|
||||||
// 防抖更新函数
|
// 防抖更新函数
|
||||||
@@ -418,7 +426,8 @@ const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
|
|||||||
fontFamily: "Monaco, monospace",
|
fontFamily: "Monaco, monospace",
|
||||||
getText: (d: any) =>
|
getText: (d: any) =>
|
||||||
d[junctionText] ? (d[junctionText] as number).toFixed(3) : "",
|
d[junctionText] ? (d[junctionText] as number).toFixed(3) : "",
|
||||||
getSize: 12,
|
getSize: 14,
|
||||||
|
fontWeight: "bold",
|
||||||
getColor: [150, 150, 255],
|
getColor: [150, 150, 255],
|
||||||
getAngle: 0,
|
getAngle: 0,
|
||||||
getTextAnchor: "middle",
|
getTextAnchor: "middle",
|
||||||
@@ -448,7 +457,8 @@ const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
|
|||||||
fontFamily: "Monaco, monospace",
|
fontFamily: "Monaco, monospace",
|
||||||
getText: (d: any) =>
|
getText: (d: any) =>
|
||||||
d[pipeText] ? (d[pipeText] as number).toFixed(3) : "",
|
d[pipeText] ? (d[pipeText] as number).toFixed(3) : "",
|
||||||
getSize: 14,
|
getSize: 12,
|
||||||
|
fontWeight: "bold",
|
||||||
getColor: [120, 128, 181],
|
getColor: [120, 128, 181],
|
||||||
getAngle: (d: any) => d.angle || 0,
|
getAngle: (d: any) => d.angle || 0,
|
||||||
getPixelOffset: [0, -8],
|
getPixelOffset: [0, -8],
|
||||||
@@ -491,13 +501,14 @@ const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
|
|||||||
const waterflowLayer = new TripsLayer({
|
const waterflowLayer = new TripsLayer({
|
||||||
id: "waterflowLayer",
|
id: "waterflowLayer",
|
||||||
data: pipeData,
|
data: pipeData,
|
||||||
getPath: (d) => (flowAnimation.current ? d.path : []),
|
getPath: (d) => d.path,
|
||||||
getTimestamps: (d) => {
|
getTimestamps: (d) => {
|
||||||
return d.timestamps; // 这些应该是与 currentTime 匹配的数值
|
return d.timestamps; // 这些应该是与 currentTime 匹配的数值
|
||||||
},
|
},
|
||||||
getColor: [0, 220, 255],
|
getColor: [0, 220, 255],
|
||||||
opacity: 0.8,
|
opacity: 0.8,
|
||||||
visible: currentZoom >= 12 && currentZoom <= 24,
|
visible:
|
||||||
|
flowAnimation.current && currentZoom >= 12 && currentZoom <= 24,
|
||||||
widthMinPixels: 5,
|
widthMinPixels: 5,
|
||||||
jointRounded: true, // 拐角变圆
|
jointRounded: true, // 拐角变圆
|
||||||
// capRounded: true, // 端点变圆
|
// capRounded: true, // 端点变圆
|
||||||
@@ -589,6 +600,10 @@ const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
|
|||||||
<>
|
<>
|
||||||
<DataContext.Provider
|
<DataContext.Provider
|
||||||
value={{
|
value={{
|
||||||
|
currentTime,
|
||||||
|
setCurrentTime,
|
||||||
|
selectedDate,
|
||||||
|
setSelectedDate,
|
||||||
currentJunctionCalData,
|
currentJunctionCalData,
|
||||||
setCurrentJunctionCalData,
|
setCurrentJunctionCalData,
|
||||||
currentPipeCalData,
|
currentPipeCalData,
|
||||||
|
|||||||
Reference in New Issue
Block a user