diff --git a/src/app/OlMap/Controls/StyleEditorPanel.tsx b/src/app/OlMap/Controls/StyleEditorPanel.tsx index 80d4044..a92167a 100644 --- a/src/app/OlMap/Controls/StyleEditorPanel.tsx +++ b/src/app/OlMap/Controls/StyleEditorPanel.tsx @@ -22,7 +22,7 @@ import WebGLVectorTileLayer from "ol/layer/WebGLVectorTile"; import VectorTileSource from "ol/source/VectorTile"; import { useData, useMap } from "../MapComponent"; -import StyleLegend, { LegendStyleConfig } from "./StyleLegend"; +import { LegendStyleConfig } from "./StyleLegend"; import { FlatStyleLike } from "ol/style/flat"; import { calculateClassification } from "@utils/breaks_classification"; @@ -55,7 +55,10 @@ interface LayerStyleState { legendConfig: LegendStyleConfig; isActive: boolean; } - +// 持久化存储 +const STORAGE_KEYS = { + layerStyleStates: "styleEditor_layerStyleStates", +}; // 预设颜色方案 const SINGLE_COLOR_PALETTES = [ { @@ -116,6 +119,7 @@ const StyleEditorPanel: React.FC = () => { setShowPipeText, setJunctionText, setPipeText, + updateLegendConfigs, } = data; const { open, close } = useNotification(); @@ -128,11 +132,6 @@ const StyleEditorPanel: React.FC = () => { const [renderLayers, setRenderLayers] = useState([]); const [selectedRenderLayer, setSelectedRenderLayer] = useState(); - const [selectedProperty, setSelectedProperty] = useState<{ - name: string; - value: string; - }>({ name: "", value: "" }); - const [availableProperties, setAvailableProperties] = useState< { name: string; value: string }[] >([]); @@ -154,8 +153,18 @@ const StyleEditorPanel: React.FC = () => { }); // 样式状态管理 - 存储多个图层的样式状态 const [layerStyleStates, setLayerStyleStates] = useState( - [] + () => { + const saved = sessionStorage.getItem(STORAGE_KEYS.layerStyleStates); + return saved ? JSON.parse(saved) : []; + } ); + // 保存layerStyleStates到sessionStorage + useEffect(() => { + sessionStorage.setItem( + STORAGE_KEYS.layerStyleStates, + JSON.stringify(layerStyleStates) + ); + }, [layerStyleStates]); // 颜色方案选择 const [singlePaletteIndex, setSinglePaletteIndex] = useState(0); const [gradientPaletteIndex, setGradientPaletteIndex] = useState(0); @@ -186,31 +195,37 @@ const StyleEditorPanel: React.FC = () => { ); // 保存当前图层的样式状态 const saveLayerStyle = useCallback( - (layerId?: string, legendConfig?: LegendStyleConfig) => { + (layerId?: string, newLegendConfig?: LegendStyleConfig) => { if (!selectedRenderLayer || !styleConfig.property) { console.warn("无法保存样式:缺少必要的图层或样式配置"); return; } if (!layerId) return; // 如果没有传入 layerId,则不保存 - const layerName = selectedRenderLayer.get("name") || `图层${layerId}`; // 如果没有传入图例配置,则创建一个默认的空配置 - const finalLegendConfig: LegendStyleConfig = legendConfig || { + const layerName = + newLegendConfig?.layerName || + selectedRenderLayer.get("name") || + `图层${layerId}`; + const property = availableProperties.find( + (p) => p.value === styleConfig.property + ); + let legendConfig: LegendStyleConfig = newLegendConfig || { layerId, layerName, - property: selectedProperty.name, + property: property?.name || styleConfig.property, colors: [], - type: "point", + type: selectedRenderLayer.get("type"), dimensions: [], breaks: [], }; + const newStyleState: LayerStyleState = { layerId, layerName, styleConfig: { ...styleConfig }, - legendConfig: { ...finalLegendConfig }, + legendConfig: { ...legendConfig }, isActive: true, }; - setLayerStyleStates((prev) => { // 检查是否已存在该图层的样式状态 const existingIndex = prev.findIndex( @@ -323,12 +338,12 @@ const StyleEditorPanel: React.FC = () => { return; } const styleConfig = layerStyleConfig.styleConfig; - const selectedRenderLayer = renderLayers.filter((layer) => { + const renderLayer = renderLayers.filter((layer) => { return layer.get("value") === layerStyleConfig.layerId; })[0]; - if (!selectedRenderLayer || !styleConfig?.property) return; - const layerType: string = selectedRenderLayer?.get("type"); - const source = selectedRenderLayer.getSource(); + if (!renderLayer || !styleConfig?.property) return; + const layerType: string = renderLayer?.get("type"); + const source = renderLayer.getSource(); if (!source) return; const breaksLength = breaks.length; @@ -416,13 +431,17 @@ const StyleEditorPanel: React.FC = () => { dynamicStyle["circle-stroke-width"] = 2; } - selectedRenderLayer.setStyle(dynamicStyle); - + renderLayer.setStyle(dynamicStyle); + // 用初始化时的样式配置更新图例配置,避免覆盖已有的图例名称和属性 + const layerId = renderLayer.get("value"); + const initLayerStyleState = layerStyleStates.find( + (s) => s.layerId === layerId + ); // 创建图例配置对象 const legendConfig: LegendStyleConfig = { - layerName: selectedRenderLayer.get("name"), - layerId: selectedRenderLayer.get("value"), - property: selectedProperty.name, + layerName: initLayerStyleState?.layerName || `图层${layerId}`, + layerId: layerId, + property: initLayerStyleState?.legendConfig.property || "", colors: colors, type: layerType, dimensions: dimensions, @@ -430,7 +449,7 @@ const StyleEditorPanel: React.FC = () => { }; // 自动保存样式状态,直接传入图例配置 setTimeout(() => { - saveLayerStyle(selectedRenderLayer.get("value"), legendConfig); + saveLayerStyle(renderLayer.get("value"), legendConfig); }, 100); }; // 重置样式 @@ -695,20 +714,7 @@ const StyleEditorPanel: React.FC = () => { setStyleConfig(cachedStyleState.styleConfig); } }, [renderLayers, selectedRenderLayer, map, renderLayers, layerStyleStates]); - // 同步属性状态 - useEffect(() => { - // 当属性值变化时自动同步 selectedProperty - if (styleConfig.property) { - const prop = availableProperties.find( - (p) => p.value === styleConfig.property - ); - if (prop) { - setSelectedProperty({ name: prop.name, value: prop.value }); - } - } else { - setSelectedProperty({ name: "", value: "" }); - } - }, [styleConfig.property, availableProperties]); + // 监听颜色类型变化,当切换到单一色时自动勾选宽度调整选项 useEffect(() => { if (styleConfig.colorType === "single") { @@ -720,14 +726,17 @@ const StyleEditorPanel: React.FC = () => { }, [styleConfig.colorType]); // 获取所有激活的图例配置 - const getActiveLegendConfigs = useCallback(() => { - return layerStyleStates - .filter((state) => state.isActive && state.legendConfig.property) - .map((state) => ({ - ...state.legendConfig, - layerName: state.layerName, - layerId: state.layerId, - })); + useEffect(() => { + if (!updateLegendConfigs) return; + updateLegendConfigs( + layerStyleStates + .filter((state) => state.isActive && state.legendConfig.property) + .map((state) => ({ + ...state.legendConfig, + layerName: state.layerName, + layerId: state.layerId, + })) + ); }, [layerStyleStates]); const getColorSetting = () => { @@ -1184,16 +1193,6 @@ const StyleEditorPanel: React.FC = () => { - {/* 显示多图层图例 */} - {getActiveLegendConfigs().length > 0 && ( -
-
- {getActiveLegendConfigs().map((config, index) => ( - - ))} -
-
- )} ); }; diff --git a/src/app/OlMap/Controls/Timeline.tsx b/src/app/OlMap/Controls/Timeline.tsx index ac08144..5cd1f24 100644 --- a/src/app/OlMap/Controls/Timeline.tsx +++ b/src/app/OlMap/Controls/Timeline.tsx @@ -55,7 +55,6 @@ const Timeline: React.FC = () => { const [isPlaying, setIsPlaying] = useState(false); const [playInterval, setPlayInterval] = useState(5000); // 毫秒 const [calculatedInterval, setCalculatedInterval] = useState(1440); // 分钟 - const [sliderValue, setSliderValue] = useState(0); const intervalRef = useRef(null); const timelineRef = useRef(null); @@ -192,7 +191,6 @@ const Timeline: React.FC = () => { const handleSliderChange = useCallback( (event: Event, newValue: number | number[]) => { const value = Array.isArray(newValue) ? newValue[0] : newValue; - setSliderValue(value); // 防抖设置currentTime,避免频繁触发数据获取 if (debounceRef.current) { clearTimeout(debounceRef.current); @@ -219,7 +217,6 @@ const Timeline: React.FC = () => { intervalRef.current = setInterval(() => { setCurrentTime((prev) => { const next = prev >= 1440 ? 0 : prev + 15; // 到达24:00后回到00:00 - setSliderValue(next); return next; }); }, playInterval); @@ -237,7 +234,6 @@ const Timeline: React.FC = () => { const handleStop = useCallback(() => { setIsPlaying(false); setCurrentTime(0); - setSliderValue(0); if (intervalRef.current) { clearInterval(intervalRef.current); intervalRef.current = null; @@ -248,7 +244,6 @@ const Timeline: React.FC = () => { const handleStepBackward = useCallback(() => { setCurrentTime((prev) => { const next = prev <= 0 ? 1440 : prev - 15; - setSliderValue(next); return next; }); }, []); @@ -256,7 +251,6 @@ const Timeline: React.FC = () => { const handleStepForward = useCallback(() => { setCurrentTime((prev) => { const next = prev >= 1440 ? 0 : prev + 15; - setSliderValue(next); return next; }); }, []); @@ -280,7 +274,6 @@ const Timeline: React.FC = () => { intervalRef.current = setInterval(() => { setCurrentTime((prev) => { const next = prev >= 1440 ? 0 : prev + 15; - setSliderValue(next); return next; }); }, newInterval); @@ -485,7 +478,7 @@ const Timeline: React.FC = () => { {/* 时间轴滑块 */} >; setPipeText?: React.Dispatch>; + updateLegendConfigs?: (configs: any[]) => void; } // 创建自定义Layer类来包装deck.gl @@ -125,6 +128,12 @@ const MapComponent: React.FC = ({ children }) => { const [pipeText, setPipeText] = useState(""); const flowAnimation = useRef(false); // 添加动画控制标志 const [currentZoom, setCurrentZoom] = useState(12); // 当前缩放级别 + // 图例配置 + const [activeLegendConfigs, setActiveLegendConfigs] = useState([]); // 存储图例配置 + // 从 StyleEditorPanel 接收图例配置的回调 + const updateLegendConfigs = (configs: any[]) => { + setActiveLegendConfigs(configs); + }; // 防抖更新函数 const debouncedUpdateData = useRef( debounce(() => { @@ -616,6 +625,7 @@ const MapComponent: React.FC = ({ children }) => { showPipeText, junctionText, pipeText, + updateLegendConfigs, }} > @@ -626,6 +636,16 @@ const MapComponent: React.FC = ({ children }) => { + {/* 图例始终渲染 */} + {activeLegendConfigs.length > 0 && ( +
+
+ {activeLegendConfigs.map((config, index) => ( + + ))} +
+
+ )} );