新增固有属性的样式计算

This commit is contained in:
JIANG
2025-12-29 11:17:43 +08:00
parent 187e8e93b4
commit 4b257aa959
2 changed files with 138 additions and 23 deletions

View File

@@ -195,6 +195,8 @@ const StyleEditorPanel: React.FC<StyleEditorPanelProps> = ({
setJunctionText,
setPipeText,
setContours,
diameterRange,
elevationRange,
} = data;
const { open } = useNotification();
@@ -398,10 +400,15 @@ const StyleEditorPanel: React.FC<StyleEditorPanelProps> = ({
layerType: "junctions" | "pipes",
styleConfig: any
) => {
const isElevation =
layerType === "junctions" && styleConfig.property === "elevation";
const isDiameter =
layerType === "pipes" && styleConfig.property === "diameter";
if (
layerType === "junctions" &&
currentJunctionCalData &&
currentJunctionCalData.length > 0
((currentJunctionCalData && currentJunctionCalData.length > 0) ||
(isElevation && elevationRange))
) {
// 应用节点样式
let junctionStyleConfigState = layerStyleStates.find(
@@ -411,6 +418,14 @@ const StyleEditorPanel: React.FC<StyleEditorPanelProps> = ({
// 更新节点数据属性
const segments = junctionStyleConfigState?.styleConfig.segments ?? 5;
let breaks: number[] = [];
const dataValues =
isElevation && elevationRange
? [elevationRange[0], elevationRange[1]]
: currentJunctionCalData?.map((d: any) => d.value) || [];
if (dataValues.length === 0) return;
if (
junctionStyleConfigState?.styleConfig.classificationMethod ===
"custom_breaks"
@@ -428,7 +443,7 @@ const StyleEditorPanel: React.FC<StyleEditorPanelProps> = ({
breaks.push(breaks[breaks.length - 1] ?? 0);
} else {
const calc = calculateClassification(
currentJunctionCalData.map((d) => d.value),
dataValues,
segments,
styleConfig.classificationMethod
);
@@ -439,12 +454,14 @@ const StyleEditorPanel: React.FC<StyleEditorPanelProps> = ({
return;
}
// 计算最大最小值,判断是否包含并插入 breaks
const data = currentJunctionCalData.map((d) => d.value);
const min_val = Math.max(
data.reduce((min, val) => Math.min(min, val), Infinity),
dataValues.reduce((min, val) => Math.min(min, val), Infinity),
0
);
const max_val = data.reduce((max, val) => Math.max(max, val), -Infinity);
const max_val = dataValues.reduce(
(max, val) => Math.max(max, val),
-Infinity
);
if (breaks.includes(min_val) === false) {
breaks.push(min_val);
breaks.sort((a, b) => a - b);
@@ -459,8 +476,8 @@ const StyleEditorPanel: React.FC<StyleEditorPanelProps> = ({
}
} else if (
layerType === "pipes" &&
currentPipeCalData &&
currentPipeCalData.length > 0
((currentPipeCalData && currentPipeCalData.length > 0) ||
(isDiameter && diameterRange))
) {
// 应用管道样式
let pipeStyleConfigState = layerStyleStates.find(
@@ -469,6 +486,14 @@ const StyleEditorPanel: React.FC<StyleEditorPanelProps> = ({
// 更新管道数据属性
const segments = pipeStyleConfigState?.styleConfig.segments ?? 5;
let breaks: number[] = [];
const dataValues =
isDiameter && diameterRange
? [diameterRange[0], diameterRange[1]]
: currentPipeCalData?.map((d: any) => d.value) || [];
if (dataValues.length === 0) return;
if (
pipeStyleConfigState?.styleConfig.classificationMethod ===
"custom_breaks"
@@ -485,7 +510,7 @@ const StyleEditorPanel: React.FC<StyleEditorPanelProps> = ({
breaks.push(breaks[breaks.length - 1] ?? 0);
} else {
const calc = calculateClassification(
currentPipeCalData.map((d) => d.value),
dataValues,
segments,
styleConfig.classificationMethod
);
@@ -496,12 +521,14 @@ const StyleEditorPanel: React.FC<StyleEditorPanelProps> = ({
return;
}
// 计算最大最小值,判断是否包含并插入 breaks
const data = currentPipeCalData.map((d) => d.value);
const min_val = Math.max(
data.reduce((min, val) => Math.min(min, val), Infinity),
dataValues.reduce((min, val) => Math.min(min, val), Infinity),
0
);
const max_val = data.reduce((max, val) => Math.max(max, val), -Infinity);
const max_val = dataValues.reduce(
(max, val) => Math.max(max, val),
-Infinity
);
if (breaks.includes(min_val) === false) {
breaks.push(min_val);
breaks.sort((a, b) => a - b);
@@ -883,16 +910,25 @@ const StyleEditorPanel: React.FC<StyleEditorPanelProps> = ({
prevStyleUpdateTriggerRef.current = styleUpdateTrigger;
const updateJunctionStyle = () => {
if (!currentJunctionCalData) return;
const junctionStyleConfigState = layerStyleStates.find(
(s) => s.layerId === "junctions"
);
const isElevation =
junctionStyleConfigState?.styleConfig.property === "elevation";
// setStyle() 会清除渲染器缓存,这是闪烁的主要原因 WebGLVectorTile.js:114-118
// 尝试考虑使用 updateStyleVariables() 更新
applyClassificationStyle(
"junctions",
junctionStyleConfigState?.styleConfig
);
if (isElevation) {
removeVectorTileSourceLoadedEvent("junctions");
return;
}
if (!currentJunctionCalData) return;
// 更新现有的 VectorTileSource
updateVectorTileSource(junctionText, currentJunctionCalData);
// 移除旧的监听器,并添加新的监听器
@@ -904,11 +940,20 @@ const StyleEditorPanel: React.FC<StyleEditorPanelProps> = ({
);
};
const updatePipeStyle = () => {
if (!currentPipeCalData) return;
const pipeStyleConfigState = layerStyleStates.find(
(s) => s.layerId === "pipes"
);
const isDiameter =
pipeStyleConfigState?.styleConfig.property === "diameter";
applyClassificationStyle("pipes", pipeStyleConfigState?.styleConfig);
if (isDiameter) {
removeVectorTileSourceLoadedEvent("pipes");
return;
}
if (!currentPipeCalData) return;
// 更新现有的 VectorTileSource
updateVectorTileSource(pipeText, currentPipeCalData);
// 移除旧的监听器,并添加新的监听器
@@ -923,14 +968,21 @@ const StyleEditorPanel: React.FC<StyleEditorPanelProps> = ({
}
return;
}
const isElevation = junctionText === "elevation";
const isDiameter = pipeText === "diameter";
if (
applyJunctionStyle &&
currentJunctionCalData &&
currentJunctionCalData.length > 0
((currentJunctionCalData && currentJunctionCalData.length > 0) ||
isElevation)
) {
updateJunctionStyle();
}
if (applyPipeStyle && currentPipeCalData && currentPipeCalData.length > 0) {
if (
applyPipeStyle &&
((currentPipeCalData && currentPipeCalData.length > 0) || isDiameter)
) {
updatePipeStyle();
}
if (!applyJunctionStyle) {
@@ -945,6 +997,8 @@ const StyleEditorPanel: React.FC<StyleEditorPanelProps> = ({
applyPipeStyle,
currentJunctionCalData,
currentPipeCalData,
elevationRange,
diameterRange,
]);
// 获取地图中的矢量图层,用于选择图层选项
@@ -1018,10 +1072,21 @@ const StyleEditorPanel: React.FC<StyleEditorPanelProps> = ({
const selectedLayerId = selectedRenderLayer?.get("value");
let dataArr: number[] = [];
if (selectedLayerId === "junctions" && currentJunctionCalData)
dataArr = currentJunctionCalData.map((d) => d.value);
else if (selectedLayerId === "pipes" && currentPipeCalData)
dataArr = currentPipeCalData.map((d) => d.value);
const isElevation =
selectedLayerId === "junctions" && styleConfig.property === "elevation";
const isDiameter =
selectedLayerId === "pipes" && styleConfig.property === "diameter";
if (isElevation && elevationRange) {
dataArr = [elevationRange[0], elevationRange[1]];
} else if (isDiameter && diameterRange) {
dataArr = [diameterRange[0], diameterRange[1]];
} else if (selectedLayerId === "junctions" && currentJunctionCalData) {
dataArr = currentJunctionCalData.map((d: any) => d.value);
} else if (selectedLayerId === "pipes" && currentPipeCalData) {
dataArr = currentPipeCalData.map((d: any) => d.value);
}
let defaultBreaks: number[] = Array.from({ length: numBreaks }, () => 0);
if (dataArr && dataArr.length > 0) {
@@ -1041,9 +1106,12 @@ const StyleEditorPanel: React.FC<StyleEditorPanelProps> = ({
}, [
styleConfig.classificationMethod,
styleConfig.segments,
styleConfig.property,
selectedRenderLayer,
currentJunctionCalData,
currentPipeCalData,
elevationRange,
diameterRange,
]);
// 初始化或调整自定义颜色数组长度

View File

@@ -63,6 +63,8 @@ interface DataContextType {
setPipeText?: React.Dispatch<React.SetStateAction<string>>;
setContours?: React.Dispatch<React.SetStateAction<any[]>>;
deckLayer?: DeckLayer;
diameterRange?: [number, number];
elevationRange?: [number, number];
}
// 跨组件传递
@@ -130,6 +132,13 @@ const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
const [showWaterflowLayer, setShowWaterflowLayer] = useState(false); // 控制等高线图层显示
const [currentZoom, setCurrentZoom] = useState(11); // 当前缩放级别
const [diameterRange, setDiameterRange] = useState<
[number, number] | undefined
>();
const [elevationRange, setElevationRange] = useState<
[number, number] | undefined
>();
// 防抖更新函数
const debouncedUpdateData = useRef(
debounce(() => {
@@ -155,6 +164,24 @@ const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
});
if (uniqueNewData.length > 0) {
setJunctionDataState((prev) => prev.concat(uniqueNewData));
setElevationRange((prev) => {
const elevations = uniqueNewData
.map((d) => d.elevation)
.filter((v) => typeof v === "number");
if (elevations.length === 0) return prev;
let newMin = elevations[0];
let newMax = elevations[0];
for (let i = 1; i < elevations.length; i++) {
if (elevations[i] < newMin) newMin = elevations[i];
if (elevations[i] > newMax) newMax = elevations[i];
}
if (!prev) {
return [newMin, newMax];
}
return [Math.min(prev[0], newMin), Math.max(prev[1], newMax)];
});
}
};
const setPipeData = (newData: any[]) => {
@@ -168,6 +195,24 @@ const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
});
if (uniqueNewData.length > 0) {
setPipeDataState((prev) => prev.concat(uniqueNewData));
setDiameterRange((prev) => {
const diameters = uniqueNewData
.map((d) => d.diameter)
.filter((v) => typeof v === "number");
if (diameters.length === 0) return prev;
let newMin = diameters[0];
let newMax = diameters[0];
for (let i = 1; i < diameters.length; i++) {
if (diameters[i] < newMin) newMin = diameters[i];
if (diameters[i] > newMax) newMax = diameters[i];
}
if (!prev) {
return [newMin, newMax];
}
return [Math.min(prev[0], newMin), Math.max(prev[1], newMax)];
});
}
};
// 配置地图数据源、图层和样式
@@ -295,8 +340,8 @@ const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
// { name: "需求量", value: "demand" },
{ name: "高程", value: "elevation" },
// 计算属性
{ name: "实际需量", value: "actualdemand" },
{ name: "水头", value: "head" },
{ name: "实际需量", value: "actual_demand" },
{ name: "水头", value: "total_head" },
{ name: "压力", value: "pressure" },
{ name: "水质", value: "quality" },
],
@@ -985,6 +1030,8 @@ const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
pipeText,
setContours,
deckLayer,
diameterRange,
elevationRange,
}}
>
<MapContext.Provider value={map}>