完善时间轴数据更新函数;完善图层显示控制函数;修复图例样式显示异常问题;
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import React, { useState, useEffect, useCallback } from "react";
|
||||
import React, { useState, useEffect, useCallback, useRef } from "react";
|
||||
|
||||
// 导入Material-UI图标和组件
|
||||
import ColorLensIcon from "@mui/icons-material/ColorLens";
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
|
||||
// 导入OpenLayers样式相关模块
|
||||
import WebGLVectorTileLayer from "ol/layer/WebGLVectorTile";
|
||||
import VectorTileSource from "ol/source/VectorTile";
|
||||
import { useData, useMap } from "../MapComponent";
|
||||
|
||||
import StyleLegend, { LegendStyleConfig } from "./StyleLegend";
|
||||
@@ -26,6 +27,8 @@ import { FlatStyleLike } from "ol/style/flat";
|
||||
|
||||
import { calculateClassification } from "@utils/breaks_classification";
|
||||
import { parseColor } from "@utils/parseColor";
|
||||
import { VectorTile } from "ol";
|
||||
import { se } from "date-fns/locale";
|
||||
|
||||
interface StyleConfig {
|
||||
property: string;
|
||||
@@ -94,7 +97,8 @@ const GRADIENT_PALETTES = [
|
||||
// 预设分类方法
|
||||
const CLASSIFICATION_METHODS = [
|
||||
{ name: "优雅分段", value: "pretty_breaks" },
|
||||
{ name: "自然间断", value: "jenks_optimized" },
|
||||
// 浏览器中实现Jenks算法性能较差,暂时移除
|
||||
// { name: "自然间断", value: "jenks_optimized" },
|
||||
];
|
||||
|
||||
const StyleEditorPanel: React.FC = () => {
|
||||
@@ -104,8 +108,10 @@ const StyleEditorPanel: React.FC = () => {
|
||||
return <div>Loading...</div>; // 或其他占位符
|
||||
}
|
||||
const {
|
||||
junctionData,
|
||||
pipeData,
|
||||
currentJunctionCalData,
|
||||
currentPipeCalData,
|
||||
junctionText,
|
||||
pipeText,
|
||||
setShowJunctionText,
|
||||
setShowPipeText,
|
||||
setJunctionText,
|
||||
@@ -114,6 +120,8 @@ const StyleEditorPanel: React.FC = () => {
|
||||
|
||||
const [applyJunctionStyle, setApplyJunctionStyle] = useState(false);
|
||||
const [applyPipeStyle, setApplyPipeStyle] = useState(false);
|
||||
const [styleUpdateTrigger, setStyleUpdateTrigger] = useState(0); // 用于触发样式更新的状态
|
||||
const prevStyleUpdateTriggerRef = useRef<number>(0);
|
||||
|
||||
const [renderLayers, setRenderLayers] = useState<WebGLVectorTileLayer[]>([]);
|
||||
const [selectedRenderLayer, setSelectedRenderLayer] =
|
||||
@@ -131,7 +139,7 @@ const StyleEditorPanel: React.FC = () => {
|
||||
classificationMethod: "pretty_breaks",
|
||||
segments: 5,
|
||||
minSize: 4,
|
||||
maxSize: 15,
|
||||
maxSize: 12,
|
||||
minStrokeWidth: 2,
|
||||
maxStrokeWidth: 6,
|
||||
fixedStrokeWidth: 3,
|
||||
@@ -142,17 +150,6 @@ const StyleEditorPanel: React.FC = () => {
|
||||
opacity: 0.9,
|
||||
adjustWidthByProperty: true,
|
||||
});
|
||||
const [legendStyleConfig, setLegendStyleConfig] = useState<LegendStyleConfig>(
|
||||
{
|
||||
layerName: "",
|
||||
layerId: "",
|
||||
property: "",
|
||||
colors: [],
|
||||
type: "point",
|
||||
dimensions: [],
|
||||
breaks: [],
|
||||
}
|
||||
);
|
||||
// 样式状态管理 - 存储多个图层的样式状态
|
||||
const [layerStyleStates, setLayerStyleStates] = useState<LayerStyleState[]>(
|
||||
[]
|
||||
@@ -185,41 +182,141 @@ const StyleEditorPanel: React.FC = () => {
|
||||
},
|
||||
[gradientPaletteIndex, parseColor]
|
||||
);
|
||||
// 应用分类样式
|
||||
const setStyleState = (layer: any) => {
|
||||
if (
|
||||
layer.get("value") !== undefined &&
|
||||
styleConfig.property !== undefined
|
||||
) {
|
||||
// 保存当前图层的样式状态
|
||||
const saveLayerStyle = useCallback(
|
||||
(layerId?: string, legendConfig?: LegendStyleConfig) => {
|
||||
if (!selectedRenderLayer || !styleConfig.property) {
|
||||
console.warn("无法保存样式:缺少必要的图层或样式配置");
|
||||
return;
|
||||
}
|
||||
if (!layerId) return; // 如果没有传入 layerId,则不保存
|
||||
const layerName = selectedRenderLayer.get("name") || `图层${layerId}`;
|
||||
// 如果没有传入图例配置,则创建一个默认的空配置
|
||||
const finalLegendConfig: LegendStyleConfig = legendConfig || {
|
||||
layerId,
|
||||
layerName,
|
||||
property: styleConfig.property,
|
||||
colors: [],
|
||||
type: "point",
|
||||
dimensions: [],
|
||||
breaks: [],
|
||||
};
|
||||
const newStyleState: LayerStyleState = {
|
||||
layerId,
|
||||
layerName,
|
||||
styleConfig: { ...styleConfig },
|
||||
legendConfig: { ...finalLegendConfig },
|
||||
isActive: true,
|
||||
};
|
||||
|
||||
setLayerStyleStates((prev) => {
|
||||
// 检查是否已存在该图层的样式状态
|
||||
const existingIndex = prev.findIndex(
|
||||
(state) => state.layerId === layerId
|
||||
);
|
||||
|
||||
if (existingIndex !== -1) {
|
||||
// 更新已存在的状态
|
||||
const updated = [...prev];
|
||||
updated[existingIndex] = newStyleState;
|
||||
return updated;
|
||||
} else {
|
||||
// 添加新的状态
|
||||
return [...prev, newStyleState];
|
||||
}
|
||||
});
|
||||
},
|
||||
[selectedRenderLayer, styleConfig]
|
||||
);
|
||||
// 设置分类样式参数,触发样式应用
|
||||
const setStyleState = () => {
|
||||
if (!selectedRenderLayer) return;
|
||||
const layerId = selectedRenderLayer.get("value");
|
||||
const property = styleConfig.property;
|
||||
if (layerId !== undefined && property !== undefined) {
|
||||
// 更新文字标签设置
|
||||
if (layer.get("value") === "junctions") {
|
||||
if (layerId === "junctions") {
|
||||
if (setJunctionText && setShowJunctionText) {
|
||||
setJunctionText(styleConfig.property);
|
||||
setJunctionText(property);
|
||||
setShowJunctionText(styleConfig.showLabels);
|
||||
setApplyJunctionStyle(true);
|
||||
saveLayerStyle(layerId);
|
||||
}
|
||||
}
|
||||
if (layer.get("value") === "pipes") {
|
||||
if (layerId === "pipes") {
|
||||
console.log(styleConfig);
|
||||
if (setPipeText && setShowPipeText) {
|
||||
setPipeText(styleConfig.property);
|
||||
setPipeText(property);
|
||||
setShowPipeText(styleConfig.showLabels);
|
||||
setApplyPipeStyle(true);
|
||||
saveLayerStyle(layerId);
|
||||
}
|
||||
}
|
||||
// 触发样式更新
|
||||
setStyleUpdateTrigger((prev) => prev + 1);
|
||||
}
|
||||
};
|
||||
const applyStyle = (layerId: string, breaks?: number[]) => {
|
||||
// 计算分类样式,并应用到对应图层
|
||||
const applyClassificationStyle = (
|
||||
layerType: "junctions" | "pipes",
|
||||
styleConfig: any
|
||||
) => {
|
||||
if (
|
||||
layerType === "junctions" &&
|
||||
currentJunctionCalData &&
|
||||
currentJunctionCalData.length > 0
|
||||
) {
|
||||
// 应用节点样式
|
||||
let junctionStyleConfigState = layerStyleStates.find(
|
||||
(s) => s.layerId === "junctions"
|
||||
);
|
||||
|
||||
// 更新节点数据属性
|
||||
const segments = junctionStyleConfigState?.styleConfig.segments ?? 5;
|
||||
const breaks = calculateClassification(
|
||||
currentJunctionCalData.map((d) => d.value),
|
||||
segments,
|
||||
styleConfig.classificationMethod
|
||||
);
|
||||
if (breaks.length === 0) {
|
||||
console.warn("计算的 breaks 为空,无法应用样式");
|
||||
return;
|
||||
}
|
||||
if (junctionStyleConfigState)
|
||||
applyLayerStyle(junctionStyleConfigState, breaks);
|
||||
} else if (
|
||||
layerType === "pipes" &&
|
||||
currentPipeCalData &&
|
||||
currentPipeCalData.length > 0
|
||||
) {
|
||||
// 应用管道样式
|
||||
let pipeStyleConfigState = layerStyleStates.find(
|
||||
(s) => s.layerId === "pipes"
|
||||
);
|
||||
// 更新管道数据属性
|
||||
const segments = pipeStyleConfigState?.styleConfig.segments ?? 5;
|
||||
const breaks = calculateClassification(
|
||||
currentPipeCalData.map((d) => d.value),
|
||||
segments,
|
||||
styleConfig.classificationMethod
|
||||
);
|
||||
if (pipeStyleConfigState) applyLayerStyle(pipeStyleConfigState, breaks);
|
||||
}
|
||||
};
|
||||
// 应用样式函数,传入 breaks 数据
|
||||
const applyLayerStyle = (
|
||||
layerStyleConfig: LayerStyleState,
|
||||
breaks?: number[]
|
||||
) => {
|
||||
// 使用传入的 breaks 数据
|
||||
if (!breaks || breaks.length === 0) {
|
||||
console.warn("没有有效的 breaks 数据");
|
||||
return;
|
||||
}
|
||||
const styleConfig = layerStyleStates.find(
|
||||
(s) => s.layerId === layerId
|
||||
)?.styleConfig;
|
||||
const selectedRenderLayer = renderLayers.find(
|
||||
(l) => l.get("id") === layerId
|
||||
);
|
||||
const styleConfig = layerStyleConfig.styleConfig;
|
||||
const selectedRenderLayer = 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();
|
||||
@@ -257,26 +354,14 @@ const StyleEditorPanel: React.FC = () => {
|
||||
(styleConfig.maxSize - styleConfig.minSize) * ratio
|
||||
);
|
||||
});
|
||||
// 创建图例配置对象
|
||||
const legendConfig: LegendStyleConfig = {
|
||||
layerName: selectedRenderLayer.get("name"),
|
||||
layerId: selectedRenderLayer.get("value"),
|
||||
property: selectedProperty.name,
|
||||
colors: colors,
|
||||
type: layerType,
|
||||
dimensions: dimensions,
|
||||
breaks: breaks,
|
||||
};
|
||||
|
||||
// 更新图例配置
|
||||
setLegendStyleConfig(legendConfig);
|
||||
// 动态生成颜色条件表达式
|
||||
const generateColorConditions = (): any[] => {
|
||||
const generateColorConditions = (property: string): any[] => {
|
||||
const conditions: any[] = ["case"];
|
||||
|
||||
for (let i = 0; i < breaks.length; i++) {
|
||||
// 添加条件:属性值 <= 当前断点
|
||||
conditions.push(["<=", ["get", styleConfig.property], breaks[i]]);
|
||||
conditions.push(["<=", ["get", property], breaks[i]]);
|
||||
// 添加对应的颜色值
|
||||
const colorObj = parseColor(colors[i]);
|
||||
const color = `rgba(${colorObj.r}, ${colorObj.g}, ${colorObj.b}, ${styleConfig.opacity})`;
|
||||
@@ -289,14 +374,12 @@ const StyleEditorPanel: React.FC = () => {
|
||||
return conditions;
|
||||
};
|
||||
// 动态生成尺寸条件表达式
|
||||
const generateDimensionConditions = (): any[] => {
|
||||
const generateDimensionConditions = (property: string): any[] => {
|
||||
const conditions: any[] = ["case"];
|
||||
|
||||
for (let i = 0; i < breaks.length; i++) {
|
||||
conditions.push(["<=", ["get", styleConfig.property], breaks[i]]);
|
||||
conditions.push(["<=", ["get", property], breaks[i]]);
|
||||
conditions.push(dimensions[i]);
|
||||
}
|
||||
|
||||
conditions.push(dimensions[dimensions.length - 1]);
|
||||
return conditions;
|
||||
};
|
||||
@@ -305,25 +388,29 @@ const StyleEditorPanel: React.FC = () => {
|
||||
|
||||
// 根据图层类型设置不同的样式属性
|
||||
if (layerType === "linestring") {
|
||||
dynamicStyle["stroke-color"] = generateColorConditions();
|
||||
dynamicStyle["stroke-width"] = generateDimensionConditions();
|
||||
dynamicStyle["stroke-color"] = generateColorConditions(
|
||||
styleConfig.property
|
||||
);
|
||||
dynamicStyle["stroke-width"] = generateDimensionConditions(
|
||||
styleConfig.property
|
||||
);
|
||||
} else if (layerType === "point") {
|
||||
dynamicStyle["circle-fill-color"] = generateColorConditions();
|
||||
dynamicStyle["circle-radius"] = generateDimensionConditions();
|
||||
dynamicStyle["circle-stroke-color"] = generateColorConditions();
|
||||
dynamicStyle["circle-fill-color"] = generateColorConditions(
|
||||
styleConfig.property
|
||||
);
|
||||
dynamicStyle["circle-radius"] = generateDimensionConditions(
|
||||
styleConfig.property
|
||||
);
|
||||
dynamicStyle["circle-stroke-color"] = generateColorConditions(
|
||||
styleConfig.property
|
||||
);
|
||||
dynamicStyle["circle-stroke-width"] = 2;
|
||||
} else {
|
||||
// 面要素
|
||||
dynamicStyle["fill-color"] = generateColorConditions();
|
||||
dynamicStyle["stroke-color"] = generateColorConditions();
|
||||
dynamicStyle["stroke-width"] = generateDimensionConditions();
|
||||
}
|
||||
|
||||
selectedRenderLayer.setStyle(dynamicStyle);
|
||||
// console.log(map?.getAllLayers());
|
||||
|
||||
// 创建图例配置对象
|
||||
const finalLegendConfig: LegendStyleConfig = {
|
||||
const legendConfig: LegendStyleConfig = {
|
||||
layerName: selectedRenderLayer.get("name"),
|
||||
layerId: selectedRenderLayer.get("value"),
|
||||
property: selectedProperty.name,
|
||||
@@ -332,28 +419,29 @@ const StyleEditorPanel: React.FC = () => {
|
||||
dimensions: dimensions,
|
||||
breaks: breaks,
|
||||
};
|
||||
|
||||
// 更新图例配置
|
||||
setLegendStyleConfig(finalLegendConfig);
|
||||
|
||||
// 自动保存样式状态,直接传入图例配置
|
||||
setTimeout(() => {
|
||||
saveLayerStyle(finalLegendConfig);
|
||||
saveLayerStyle(selectedRenderLayer.get("value"), legendConfig);
|
||||
}, 100);
|
||||
};
|
||||
// 重置样式
|
||||
const resetStyle = useCallback(() => {
|
||||
if (!selectedRenderLayer) return;
|
||||
|
||||
// 重置 WebGL 图层样式
|
||||
const defaultFlatStyle: FlatStyleLike = {
|
||||
"stroke-width": 2,
|
||||
"stroke-color": `rgba(51, 153, 204, 0.9)`,
|
||||
"fill-color": `rgba(51, 153, 204, 0.5)`,
|
||||
"circle-radius": 7,
|
||||
"circle-stroke-width": 2,
|
||||
"circle-stroke-color": `rgba(51, 153, 204, 0.9)`,
|
||||
"circle-fill-color": `rgba(51, 153, 204, 0.5)`,
|
||||
"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
|
||||
],
|
||||
};
|
||||
selectedRenderLayer.setStyle(defaultFlatStyle);
|
||||
|
||||
@@ -366,85 +454,190 @@ const StyleEditorPanel: React.FC = () => {
|
||||
// 重置样式应用状态
|
||||
if (layerId === "junctions") {
|
||||
setApplyJunctionStyle(false);
|
||||
if (setShowJunctionText) setShowJunctionText(false);
|
||||
if (setJunctionText) setJunctionText("");
|
||||
} else if (layerId === "pipes") {
|
||||
setApplyPipeStyle(false);
|
||||
if (setShowPipeText) setShowPipeText(false);
|
||||
if (setPipeText) setPipeText("");
|
||||
}
|
||||
}
|
||||
}, [selectedRenderLayer]);
|
||||
// 更新当前 VectorTileSource 中的所有缓冲要素属性
|
||||
const updateVectorTileSource = (property: string, data: any[]) => {
|
||||
if (!map) return;
|
||||
|
||||
const vectorTileSources = map
|
||||
.getAllLayers()
|
||||
.filter((layer) => layer instanceof WebGLVectorTileLayer)
|
||||
.map((layer) => layer.getSource() as VectorTileSource)
|
||||
.filter((source) => source);
|
||||
|
||||
if (!vectorTileSources.length) return;
|
||||
|
||||
// 创建 id 到 value 的映射
|
||||
const dataMap = new Map<string, number>();
|
||||
data.forEach((d: any) => {
|
||||
dataMap.set(d.ID, d.value || 0);
|
||||
});
|
||||
|
||||
// 直接遍历所有瓦片和要素,无需分批处理
|
||||
vectorTileSources.forEach((vectorTileSource) => {
|
||||
const sourceTiles = vectorTileSource.sourceTiles_;
|
||||
|
||||
Object.values(sourceTiles).forEach((vectorTile) => {
|
||||
const renderFeatures = vectorTile.getFeatures();
|
||||
if (!renderFeatures || renderFeatures.length === 0) return;
|
||||
// 直接更新要素属性
|
||||
renderFeatures.forEach((renderFeature) => {
|
||||
const featureId = renderFeature.get("id");
|
||||
const value = dataMap.get(featureId);
|
||||
if (value !== undefined) {
|
||||
(renderFeature as any).properties_[property] = value;
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
// 新增事件,监听 VectorTileSource 的 tileloadend 事件,为新增瓦片数据动态更新要素属性
|
||||
const [tileLoadListeners, setTileLoadListeners] = useState<
|
||||
Map<VectorTileSource, (event: any) => void>
|
||||
>(new Map());
|
||||
const attachVectorTileSourceLoadedEvent = (
|
||||
layerId: string,
|
||||
property: string,
|
||||
data: any[]
|
||||
) => {
|
||||
if (!map) return;
|
||||
const vectorTileSource = map
|
||||
.getAllLayers()
|
||||
.filter((layer) => layer.get("value") === layerId)
|
||||
.map((layer) => layer.getSource() as VectorTileSource)
|
||||
.filter((source) => source)[0];
|
||||
if (!vectorTileSource) return;
|
||||
// 创建 id 到 value 的映射
|
||||
const dataMap = new Map<string, number>();
|
||||
data.forEach((d: any) => {
|
||||
dataMap.set(d.ID, d.value || 0);
|
||||
});
|
||||
// 新增监听器并保存
|
||||
const newListeners = new Map<VectorTileSource, (event: any) => void>();
|
||||
|
||||
const listener = (event: any) => {
|
||||
try {
|
||||
if (event.tile instanceof VectorTile) {
|
||||
const renderFeatures = event.tile.getFeatures();
|
||||
if (!renderFeatures || renderFeatures.length === 0) return;
|
||||
// 直接更新要素属性
|
||||
renderFeatures.forEach((renderFeature: any) => {
|
||||
const featureId = renderFeature.get("id");
|
||||
const value = dataMap.get(featureId);
|
||||
if (value !== undefined) {
|
||||
(renderFeature as any).properties_[property] = value;
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error processing tile load event:", error);
|
||||
}
|
||||
};
|
||||
|
||||
vectorTileSource.on("tileloadend", listener);
|
||||
newListeners.set(vectorTileSource, listener);
|
||||
setTileLoadListeners(newListeners);
|
||||
};
|
||||
// 新增函数:取消对应 layerId 已添加的 on 事件
|
||||
const removeVectorTileSourceLoadedEvent = (layerId: string) => {
|
||||
if (!map) return;
|
||||
const vectorTileSource = map
|
||||
.getAllLayers()
|
||||
.filter((layer) => layer.get("value") === layerId)
|
||||
.map((layer) => layer.getSource() as VectorTileSource)
|
||||
.filter((source) => source)[0];
|
||||
if (!vectorTileSource) return;
|
||||
const listener = tileLoadListeners.get(vectorTileSource);
|
||||
if (listener) {
|
||||
vectorTileSource.un("tileloadend", listener);
|
||||
setTileLoadListeners((prev) => {
|
||||
const newMap = new Map(prev);
|
||||
newMap.delete(vectorTileSource);
|
||||
return newMap;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 监听数据变化,重新应用样式。由样式应用按钮触发,或由数据变化触发
|
||||
useEffect(() => {
|
||||
if (applyJunctionStyle && junctionData.length > 0) {
|
||||
// 应用节点样式
|
||||
// 判断此次触发是否由用户点击“应用”按钮引起
|
||||
const isUserTrigger =
|
||||
styleUpdateTrigger !== prevStyleUpdateTriggerRef.current;
|
||||
// 更新 prevStyleUpdateTriggerRef
|
||||
prevStyleUpdateTriggerRef.current = styleUpdateTrigger;
|
||||
|
||||
const updateJunctionStyle = () => {
|
||||
if (!currentJunctionCalData) return;
|
||||
const junctionStyleConfigState = layerStyleStates.find(
|
||||
(s) => s.layerId === "junctions"
|
||||
);
|
||||
if (!junctionStyleConfigState) return;
|
||||
const segments = junctionStyleConfigState?.styleConfig.segments;
|
||||
const breaks = calculateClassification(
|
||||
junctionData,
|
||||
segments,
|
||||
styleConfig.classificationMethod
|
||||
applyClassificationStyle(
|
||||
"junctions",
|
||||
junctionStyleConfigState?.styleConfig
|
||||
);
|
||||
applyStyle(junctionStyleConfigState.layerId, breaks);
|
||||
}
|
||||
if (applyPipeStyle && pipeData.length > 0) {
|
||||
// 应用管道样式
|
||||
// 更新现有的 VectorTileSource
|
||||
updateVectorTileSource(junctionText, currentJunctionCalData);
|
||||
// 移除旧的监听器,并添加新的监听器
|
||||
removeVectorTileSourceLoadedEvent("junctions");
|
||||
attachVectorTileSourceLoadedEvent(
|
||||
"junctions",
|
||||
junctionText,
|
||||
currentJunctionCalData
|
||||
);
|
||||
};
|
||||
const updatePipeStyle = () => {
|
||||
if (!currentPipeCalData) return;
|
||||
const pipeStyleConfigState = layerStyleStates.find(
|
||||
(s) => s.layerId === "pipes"
|
||||
);
|
||||
if (!pipeStyleConfigState) return;
|
||||
const segments = pipeStyleConfigState?.styleConfig.segments;
|
||||
const breaks = calculateClassification(
|
||||
pipeData,
|
||||
segments,
|
||||
styleConfig.classificationMethod
|
||||
);
|
||||
applyStyle(pipeStyleConfigState.layerId, breaks);
|
||||
}
|
||||
}, [junctionData, pipeData, applyJunctionStyle, applyPipeStyle]);
|
||||
// 样式状态管理功能
|
||||
// 保存当前图层的样式状态
|
||||
const saveLayerStyle = useCallback(
|
||||
(overrideLegendConfig?: LegendStyleConfig) => {
|
||||
if (!selectedRenderLayer || !styleConfig.property) {
|
||||
console.warn("无法保存样式:缺少必要的图层或样式配置");
|
||||
return;
|
||||
applyClassificationStyle("pipes", pipeStyleConfigState?.styleConfig);
|
||||
// 更新现有的 VectorTileSource
|
||||
updateVectorTileSource(pipeText, currentPipeCalData);
|
||||
// 移除旧的监听器,并添加新的监听器
|
||||
removeVectorTileSourceLoadedEvent("pipes");
|
||||
attachVectorTileSourceLoadedEvent("pipes", pipeText, currentPipeCalData);
|
||||
};
|
||||
if (isUserTrigger) {
|
||||
if (selectedRenderLayer?.get("value") === "junctions") {
|
||||
updateJunctionStyle();
|
||||
} else if (selectedRenderLayer?.get("value") === "pipes") {
|
||||
updatePipeStyle();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (
|
||||
applyJunctionStyle &&
|
||||
currentJunctionCalData &&
|
||||
currentJunctionCalData.length > 0
|
||||
) {
|
||||
updateJunctionStyle();
|
||||
}
|
||||
if (applyPipeStyle && currentPipeCalData && currentPipeCalData.length > 0) {
|
||||
updatePipeStyle();
|
||||
}
|
||||
if (!applyJunctionStyle) {
|
||||
removeVectorTileSourceLoadedEvent("junctions");
|
||||
}
|
||||
if (!applyPipeStyle) {
|
||||
removeVectorTileSourceLoadedEvent("pipes");
|
||||
}
|
||||
}, [
|
||||
styleUpdateTrigger,
|
||||
applyJunctionStyle,
|
||||
applyPipeStyle,
|
||||
currentJunctionCalData,
|
||||
currentPipeCalData,
|
||||
]);
|
||||
|
||||
const layerId = selectedRenderLayer.get("value");
|
||||
const layerName = selectedRenderLayer.get("name") || `图层${layerId}`;
|
||||
|
||||
// 使用传入的图例配置,或者使用当前状态的图例配置
|
||||
const finalLegendConfig = overrideLegendConfig || legendStyleConfig;
|
||||
|
||||
const newStyleState: LayerStyleState = {
|
||||
layerId,
|
||||
layerName,
|
||||
styleConfig: { ...styleConfig },
|
||||
legendConfig: { ...finalLegendConfig },
|
||||
isActive: true,
|
||||
};
|
||||
|
||||
setLayerStyleStates((prev) => {
|
||||
// 检查是否已存在该图层的样式状态
|
||||
const existingIndex = prev.findIndex(
|
||||
(state) => state.layerId === layerId
|
||||
);
|
||||
|
||||
if (existingIndex !== -1) {
|
||||
// 更新已存在的状态
|
||||
const updated = [...prev];
|
||||
updated[existingIndex] = newStyleState;
|
||||
return updated;
|
||||
} else {
|
||||
// 添加新的状态
|
||||
return [...prev, newStyleState];
|
||||
}
|
||||
});
|
||||
},
|
||||
[selectedRenderLayer, styleConfig, legendStyleConfig]
|
||||
);
|
||||
// 获取地图中的矢量图层
|
||||
// 获取地图中的矢量图层,用于选择图层选项
|
||||
useEffect(() => {
|
||||
if (!map) return;
|
||||
|
||||
@@ -461,18 +654,16 @@ const StyleEditorPanel: React.FC = () => {
|
||||
|
||||
updateVisibleLayers();
|
||||
}, [map]);
|
||||
// 获取选中图层的属性
|
||||
// 获取选中图层的属性,并检查是否有已缓存的样式状态
|
||||
useEffect(() => {
|
||||
// 如果没有矢量图层或没有选中图层,清空属性列表
|
||||
if (!renderLayers || renderLayers.length === 0) {
|
||||
setAvailableProperties([]);
|
||||
// console.log("没有可用的矢量图层");
|
||||
return;
|
||||
}
|
||||
// 如果没有选中图层,清空属性列表
|
||||
if (!selectedRenderLayer) {
|
||||
setAvailableProperties([]);
|
||||
// console.log("没有选中的图层");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -491,11 +682,8 @@ const StyleEditorPanel: React.FC = () => {
|
||||
const cachedStyleState = layerStyleStates.find(
|
||||
(state) => state.layerId === layerId
|
||||
);
|
||||
|
||||
if (cachedStyleState) {
|
||||
setStyleConfig(cachedStyleState.styleConfig);
|
||||
setLegendStyleConfig(cachedStyleState.legendConfig);
|
||||
// console.log(`已自动恢复图层 ${cachedStyleState.layerName} 的样式状态`);
|
||||
}
|
||||
}, [renderLayers, selectedRenderLayer, map, renderLayers, layerStyleStates]);
|
||||
// 同步属性状态
|
||||
@@ -643,8 +831,8 @@ const StyleEditorPanel: React.FC = () => {
|
||||
minSize: value as number,
|
||||
}))
|
||||
}
|
||||
min={5}
|
||||
max={15}
|
||||
min={2}
|
||||
max={8}
|
||||
step={1}
|
||||
size="small"
|
||||
/>
|
||||
@@ -661,8 +849,8 @@ const StyleEditorPanel: React.FC = () => {
|
||||
maxSize: value as number,
|
||||
}))
|
||||
}
|
||||
min={20}
|
||||
max={30}
|
||||
min={10}
|
||||
max={16}
|
||||
step={1}
|
||||
size="small"
|
||||
/>
|
||||
@@ -966,7 +1154,7 @@ const StyleEditorPanel: React.FC = () => {
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={() => {
|
||||
setStyleState(selectedRenderLayer);
|
||||
setStyleState();
|
||||
}}
|
||||
disabled={!selectedRenderLayer || !styleConfig.property}
|
||||
startIcon={<ApplyIcon />}
|
||||
@@ -989,7 +1177,7 @@ const StyleEditorPanel: React.FC = () => {
|
||||
</div>
|
||||
{/* 显示多图层图例 */}
|
||||
{getActiveLegendConfigs().length > 0 && (
|
||||
<div className=" absolute bottom-40 right-4 shadow-lg flex flex-row items-end max-w-screen-lg overflow-x-auto z-10">
|
||||
<div className=" absolute bottom-40 right-4 drop-shadow-xl flex flex-row items-end max-w-screen-lg overflow-x-auto z-10">
|
||||
<div className="flex flex-row gap-3">
|
||||
{getActiveLegendConfigs().map((config, index) => (
|
||||
<StyleLegend key={`${config.layerId}-${index}`} {...config} />
|
||||
|
||||
Reference in New Issue
Block a user