更新地图样式;调整时间轴,新增前进/后退一天按钮;新增爆管分析页面
This commit is contained in:
16
src/app/(main)/burst-pipe-analysis/page.tsx
Normal file
16
src/app/(main)/burst-pipe-analysis/page.tsx
Normal file
@@ -0,0 +1,16 @@
|
||||
"use client";
|
||||
|
||||
import MapComponent from "@app/OlMap/MapComponent";
|
||||
import MapToolbar from "@app/OlMap/Controls/Toolbar";
|
||||
import BurstPipeAnalysisPanel from "@/components/olmap/BurstPipeAnalysisPanel";
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<div className="relative w-full h-full overflow-hidden">
|
||||
<MapComponent>
|
||||
{/* <MapToolbar hiddenButtons={["style"]} /> */}
|
||||
<BurstPipeAnalysisPanel />
|
||||
</MapComponent>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -78,7 +78,7 @@ export default function Home() {
|
||||
<div className="relative w-full h-full overflow-hidden">
|
||||
<MapComponent>
|
||||
<MapToolbar />
|
||||
<div className="absolute bottom-4 left-1/2 -translate-x-1/2 z-10 w-[800px] opacity-90 hover:opacity-100 transition-opacity duration-300">
|
||||
<div className="absolute bottom-4 left-1/2 -translate-x-1/2 z-10 w-[920px] opacity-90 hover:opacity-100 transition-opacity duration-300">
|
||||
<Timeline />
|
||||
</div>
|
||||
</MapComponent>
|
||||
|
||||
@@ -29,6 +29,7 @@ import { calculateClassification } from "@utils/breaks_classification";
|
||||
import { parseColor } from "@utils/parseColor";
|
||||
import { VectorTile } from "ol";
|
||||
import { useNotification } from "@refinedev/core";
|
||||
import { config } from "@/config/config";
|
||||
|
||||
interface StyleConfig {
|
||||
property: string;
|
||||
@@ -64,6 +65,9 @@ const SINGLE_COLOR_PALETTES = [
|
||||
{
|
||||
color: "rgba(51, 153, 204, 1)",
|
||||
},
|
||||
{
|
||||
color: "rgba(255, 138, 92, 1)",
|
||||
},
|
||||
{
|
||||
color: "rgba(204, 51, 51, 1)",
|
||||
},
|
||||
@@ -405,6 +409,25 @@ const StyleEditorPanel: React.FC = () => {
|
||||
conditions.push(dimensions[i]);
|
||||
}
|
||||
conditions.push(dimensions[dimensions.length - 1]);
|
||||
console.log("生成的尺寸条件表达式:", conditions);
|
||||
return conditions;
|
||||
};
|
||||
const generateDimensionPointConditions = (property: string): any[] => {
|
||||
const conditions: any[] = ["case"];
|
||||
for (let i = 0; i < breaks.length; i++) {
|
||||
conditions.push(["<=", ["get", property], breaks[i]]);
|
||||
conditions.push([
|
||||
"interpolate",
|
||||
["linear"],
|
||||
["zoom"],
|
||||
12,
|
||||
1, // 使用配置的最小尺寸
|
||||
24,
|
||||
dimensions[i],
|
||||
]);
|
||||
}
|
||||
conditions.push(dimensions[dimensions.length - 1]);
|
||||
console.log("生成的点尺寸条件表达式:", conditions);
|
||||
return conditions;
|
||||
};
|
||||
// 创建基于 breaks 的动态 FlatStyle
|
||||
@@ -422,7 +445,7 @@ const StyleEditorPanel: React.FC = () => {
|
||||
dynamicStyle["circle-fill-color"] = generateColorConditions(
|
||||
styleConfig.property
|
||||
);
|
||||
dynamicStyle["circle-radius"] = generateDimensionConditions(
|
||||
dynamicStyle["circle-radius"] = generateDimensionPointConditions(
|
||||
styleConfig.property
|
||||
);
|
||||
dynamicStyle["circle-stroke-color"] = generateColorConditions(
|
||||
@@ -456,21 +479,7 @@ const StyleEditorPanel: React.FC = () => {
|
||||
const resetStyle = useCallback(() => {
|
||||
if (!selectedRenderLayer) return;
|
||||
// 重置 WebGL 图层样式
|
||||
const defaultFlatStyle: FlatStyleLike = {
|
||||
"stroke-width": 3,
|
||||
"stroke-color": "rgba(51, 153, 204, 0.9)",
|
||||
"circle-fill-color": "rgba(255,255,255,0.4)",
|
||||
"circle-stroke-color": "rgba(255,255,255,0.9)",
|
||||
"circle-radius": [
|
||||
"interpolate",
|
||||
["linear"],
|
||||
["zoom"],
|
||||
12,
|
||||
1, // 在缩放级别 12 时,圆形半径为 1px
|
||||
24,
|
||||
12, // 在缩放级别 24 时,圆形半径为 12px
|
||||
],
|
||||
};
|
||||
const defaultFlatStyle: FlatStyleLike = config.mapDefaultStyle;
|
||||
selectedRenderLayer.setStyle(defaultFlatStyle);
|
||||
|
||||
// 删除对应图层的样式状态,从而移除图例显示
|
||||
@@ -531,6 +540,7 @@ const StyleEditorPanel: React.FC = () => {
|
||||
const [tileLoadListeners, setTileLoadListeners] = useState<
|
||||
Map<VectorTileSource, (event: any) => void>
|
||||
>(new Map());
|
||||
|
||||
const attachVectorTileSourceLoadedEvent = (
|
||||
layerId: string,
|
||||
property: string,
|
||||
|
||||
@@ -23,6 +23,7 @@ import { AdapterDateFns } from "@mui/x-date-pickers/AdapterDateFns";
|
||||
import { zhCN } from "date-fns/locale";
|
||||
import { PlayArrow, Pause, Stop, Refresh } from "@mui/icons-material";
|
||||
import { TbRewindBackward15, TbRewindForward15 } from "react-icons/tb";
|
||||
import { FiSkipBack, FiSkipForward } from "react-icons/fi";
|
||||
import { useData } from "../MapComponent";
|
||||
import { config } from "@/config/config";
|
||||
import { useMap } from "../MapComponent";
|
||||
@@ -210,7 +211,7 @@ const Timeline: React.FC = () => {
|
||||
type: "error",
|
||||
message: "请至少设定并应用一个图层的样式。",
|
||||
});
|
||||
return;
|
||||
// return;
|
||||
}
|
||||
setIsPlaying(true);
|
||||
|
||||
@@ -233,7 +234,10 @@ const Timeline: React.FC = () => {
|
||||
|
||||
const handleStop = useCallback(() => {
|
||||
setIsPlaying(false);
|
||||
setCurrentTime(0);
|
||||
// 设置为当前时间
|
||||
const currentTime = new Date();
|
||||
const minutes = currentTime.getHours() * 60 + currentTime.getMinutes();
|
||||
setCurrentTime(minutes); // 组件卸载时重置时间
|
||||
if (intervalRef.current) {
|
||||
clearInterval(intervalRef.current);
|
||||
intervalRef.current = null;
|
||||
@@ -241,6 +245,20 @@ const Timeline: React.FC = () => {
|
||||
}, []);
|
||||
|
||||
// 步进控制
|
||||
const handleDayStepBackward = useCallback(() => {
|
||||
setSelectedDate((prev) => {
|
||||
const newDate = new Date(prev);
|
||||
newDate.setDate(newDate.getDate() - 1);
|
||||
return newDate;
|
||||
});
|
||||
}, []);
|
||||
const handleDayStepForward = useCallback(() => {
|
||||
setSelectedDate((prev) => {
|
||||
const newDate = new Date(prev);
|
||||
newDate.setDate(newDate.getDate() + 1);
|
||||
return newDate;
|
||||
});
|
||||
}, []);
|
||||
const handleStepBackward = useCallback(() => {
|
||||
setCurrentTime((prev) => {
|
||||
const next = prev <= 0 ? 1440 : prev - 15;
|
||||
@@ -299,7 +317,7 @@ const Timeline: React.FC = () => {
|
||||
type: "error",
|
||||
message: "请至少设定并应用一个图层的样式。",
|
||||
});
|
||||
return;
|
||||
// return;
|
||||
}
|
||||
fetchFrameData(
|
||||
currentTimeToDate(selectedDate, currentTime),
|
||||
@@ -311,7 +329,12 @@ const Timeline: React.FC = () => {
|
||||
|
||||
// 组件卸载时清理定时器和防抖
|
||||
useEffect(() => {
|
||||
setCurrentTime(0); // 组件卸载时重置时间
|
||||
// 设置为当前时间
|
||||
const currentTime = new Date();
|
||||
const minutes = currentTime.getHours() * 60 + currentTime.getMinutes();
|
||||
// 找到最近的前15分钟刻度
|
||||
const roundedMinutes = Math.floor(minutes / 15) * 15;
|
||||
setCurrentTime(roundedMinutes); // 组件卸载时重置时间
|
||||
|
||||
return () => {
|
||||
if (intervalRef.current) {
|
||||
@@ -363,6 +386,15 @@ const Timeline: React.FC = () => {
|
||||
alignItems="center"
|
||||
sx={{ mb: 2, flexWrap: "wrap", gap: 1 }}
|
||||
>
|
||||
<Tooltip title="后退一天">
|
||||
<IconButton
|
||||
color="primary"
|
||||
onClick={handleDayStepBackward}
|
||||
size="small"
|
||||
>
|
||||
<FiSkipBack />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
{/* 日期选择器 */}
|
||||
<DatePicker
|
||||
label="模拟数据日期选择"
|
||||
@@ -379,9 +411,20 @@ const Timeline: React.FC = () => {
|
||||
sx={{ width: 180, "& .MuiInputBase-root": { height: 40 } }}
|
||||
maxDate={new Date()} // 禁止选取未来的日期
|
||||
/>
|
||||
|
||||
<Tooltip title="前进一天">
|
||||
<IconButton
|
||||
color="primary"
|
||||
onClick={handleDayStepForward}
|
||||
size="small"
|
||||
disabled={
|
||||
selectedDate.toDateString() === new Date().toDateString()
|
||||
}
|
||||
>
|
||||
<FiSkipForward />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
{/* 播放控制按钮 */}
|
||||
<Box sx={{ display: "flex", gap: 1 }}>
|
||||
<Box sx={{ display: "flex", gap: 1 }} className="ml-4">
|
||||
{/* 播放间隔选择 */}
|
||||
<FormControl size="small" sx={{ minWidth: 100 }}>
|
||||
<InputLabel>播放间隔</InputLabel>
|
||||
@@ -434,7 +477,7 @@ const Timeline: React.FC = () => {
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</Box>
|
||||
<Box sx={{ display: "flex", gap: 1 }}>
|
||||
<Box sx={{ display: "flex", gap: 1 }} className="ml-4">
|
||||
{/* 强制计算时间段 */}
|
||||
<FormControl size="small" sx={{ minWidth: 100 }}>
|
||||
<InputLabel>计算时间段</InputLabel>
|
||||
|
||||
@@ -21,6 +21,7 @@ import VectorTileSource from "ol/source/VectorTile";
|
||||
import TileState from "ol/TileState";
|
||||
import { toLonLat } from "ol/proj";
|
||||
import { booleanIntersects, buffer, point, toWgs84 } from "@turf/turf";
|
||||
// import { handleMapClickSelectFeatures as mapClickSelectFeatures } from "@/utils/mapQueryService";
|
||||
import RenderFeature from "ol/render/Feature";
|
||||
|
||||
import { config } from "@/config/config";
|
||||
@@ -329,7 +330,13 @@ const Toolbar: React.FC<ToolbarProps> = ({ hiddenButtons }) => {
|
||||
},
|
||||
[map, highlightLayer, setHighlightFeature]
|
||||
);
|
||||
|
||||
// const handleMapClickSelectFeatures = useCallback(
|
||||
// (event: { coordinate: number[] }) => {
|
||||
// if (!map) return;
|
||||
// mapClickSelectFeatures(event, map, setHighlightFeature); // 调用导入的函数
|
||||
// },
|
||||
// [map, setHighlightFeature]
|
||||
// );
|
||||
// 添加矢量属性查询事件监听器
|
||||
useEffect(() => {
|
||||
if (!activeTools.includes("info") || !map) return;
|
||||
|
||||
@@ -104,9 +104,9 @@ const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
|
||||
|
||||
const [map, setMap] = useState<OlMap>();
|
||||
// currentCalData 用于存储当前计算结果
|
||||
const [currentTime, setCurrentTime] = useState<number>(-1); // 默认-1表示未选择时间
|
||||
const [selectedDate, setSelectedDate] = useState<Date>(new Date("2025-9-17"));
|
||||
// const [selectedDate, setSelectedDate] = useState<Date>(new Date()); // 默认今天
|
||||
const [currentTime, setCurrentTime] = useState<number>(-1); // 默认选择当前时间
|
||||
// const [selectedDate, setSelectedDate] = useState<Date>(new Date("2025-9-17"));
|
||||
const [selectedDate, setSelectedDate] = useState<Date>(new Date()); // 默认今天
|
||||
|
||||
const [currentJunctionCalData, setCurrentJunctionCalData] = useState<any[]>(
|
||||
[]
|
||||
@@ -174,21 +174,7 @@ const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
|
||||
setPipeDataState((prev) => [...prev, ...uniqueNewData]);
|
||||
}
|
||||
};
|
||||
const defaultFlatStyle: FlatStyleLike = {
|
||||
"stroke-width": 3,
|
||||
"stroke-color": "rgba(51, 153, 204, 0.9)",
|
||||
"circle-fill-color": "rgba(255,255,255,0.4)",
|
||||
"circle-stroke-color": "rgba(255,255,255,0.9)",
|
||||
"circle-radius": [
|
||||
"interpolate",
|
||||
["linear"],
|
||||
["zoom"],
|
||||
12,
|
||||
1, // 在缩放级别 12 时,圆形半径为 1px
|
||||
24,
|
||||
12, // 在缩放级别 24 时,圆形半径为 12px
|
||||
],
|
||||
};
|
||||
const defaultFlatStyle: FlatStyleLike = config.mapDefaultStyle;
|
||||
// 矢量瓦片数据源和图层
|
||||
const junctionSource = new VectorTileSource({
|
||||
url: `${mapUrl}/gwc/service/tms/1.0.0/TJWater:geo_junctions_mat@WebMercatorQuad@pbf/{z}/{x}/{-y}.pbf`, // 替换为你的 MVT 瓦片服务 URL
|
||||
@@ -435,9 +421,9 @@ const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
|
||||
fontFamily: "Monaco, monospace",
|
||||
getText: (d: any) =>
|
||||
d[junctionText] ? (d[junctionText] as number).toFixed(3) : "",
|
||||
getSize: 14,
|
||||
getSize: 18,
|
||||
fontWeight: "bold",
|
||||
getColor: [150, 150, 255],
|
||||
getColor: [255, 138, 92],
|
||||
getAngle: 0,
|
||||
getTextAnchor: "middle",
|
||||
getAlignmentBaseline: "center",
|
||||
@@ -455,8 +441,8 @@ const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
|
||||
fontSize: 64,
|
||||
buffer: 6,
|
||||
},
|
||||
outlineWidth: 10,
|
||||
outlineColor: [255, 255, 255, 255],
|
||||
// outlineWidth: 10,
|
||||
// outlineColor: [242, 244, 246, 255],
|
||||
}),
|
||||
new TextLayer({
|
||||
id: "pipeTextLayer",
|
||||
@@ -466,9 +452,9 @@ const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
|
||||
fontFamily: "Monaco, monospace",
|
||||
getText: (d: any) =>
|
||||
d[pipeText] ? (d[pipeText] as number).toFixed(3) : "",
|
||||
getSize: 12,
|
||||
getSize: 18,
|
||||
fontWeight: "bold",
|
||||
getColor: [120, 128, 181],
|
||||
getColor: [51, 153, 204],
|
||||
getAngle: (d: any) => d.angle || 0,
|
||||
getPixelOffset: [0, -8],
|
||||
getTextAnchor: "middle",
|
||||
@@ -485,8 +471,8 @@ const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
|
||||
fontSize: 64,
|
||||
buffer: 6,
|
||||
},
|
||||
outlineWidth: 10,
|
||||
outlineColor: [255, 255, 255, 255],
|
||||
// outlineWidth: 10,
|
||||
// outlineColor: [242, 244, 246, 255],
|
||||
}),
|
||||
];
|
||||
deck.setProps({ layers: newLayers });
|
||||
|
||||
Reference in New Issue
Block a user