新增等值线图样式自定义功能
This commit is contained in:
@@ -1,6 +1,5 @@
|
|||||||
import React, { useState, useEffect, useCallback } from "react";
|
import React, { useState, useEffect, useCallback } from "react";
|
||||||
import { useData, useMap } from "../MapComponent";
|
import { useData, useMap } from "../MapComponent";
|
||||||
import { Layer } from "ol/layer";
|
|
||||||
import { Checkbox, FormControlLabel } from "@mui/material";
|
import { Checkbox, FormControlLabel } from "@mui/material";
|
||||||
import WebGLVectorTileLayer from "ol/layer/WebGLVectorTile";
|
import WebGLVectorTileLayer from "ol/layer/WebGLVectorTile";
|
||||||
import VectorLayer from "ol/layer/Vector";
|
import VectorLayer from "ol/layer/Vector";
|
||||||
|
|||||||
@@ -193,7 +193,7 @@ const StyleEditorPanel: React.FC<StyleEditorPanelProps> = ({
|
|||||||
setWaterflowLayerAvailable,
|
setWaterflowLayerAvailable,
|
||||||
setJunctionText,
|
setJunctionText,
|
||||||
setPipeText,
|
setPipeText,
|
||||||
deckLayer,
|
setContours,
|
||||||
} = data;
|
} = data;
|
||||||
|
|
||||||
const { open } = useNotification();
|
const { open } = useNotification();
|
||||||
@@ -444,8 +444,10 @@ const StyleEditorPanel: React.FC<StyleEditorPanelProps> = ({
|
|||||||
breaks.push(max_val);
|
breaks.push(max_val);
|
||||||
breaks.sort((a, b) => a - b);
|
breaks.sort((a, b) => a - b);
|
||||||
}
|
}
|
||||||
if (junctionStyleConfigState)
|
if (junctionStyleConfigState) {
|
||||||
applyLayerStyle(junctionStyleConfigState, breaks);
|
applyLayerStyle(junctionStyleConfigState, breaks);
|
||||||
|
applyContourLayerStyle(junctionStyleConfigState, breaks);
|
||||||
|
}
|
||||||
} else if (
|
} else if (
|
||||||
layerType === "pipes" &&
|
layerType === "pipes" &&
|
||||||
currentPipeCalData &&
|
currentPipeCalData &&
|
||||||
@@ -661,6 +663,67 @@ const StyleEditorPanel: React.FC<StyleEditorPanelProps> = ({
|
|||||||
saveLayerStyle(renderLayer.get("value"), legendConfig);
|
saveLayerStyle(renderLayer.get("value"), legendConfig);
|
||||||
}, 100);
|
}, 100);
|
||||||
};
|
};
|
||||||
|
// 应用样式函数,传入 breaks 数据
|
||||||
|
const applyContourLayerStyle = (
|
||||||
|
layerStyleConfig: LayerStyleState,
|
||||||
|
breaks?: number[]
|
||||||
|
) => {
|
||||||
|
// 使用传入的 breaks 数据
|
||||||
|
if (!breaks || breaks.length === 0) {
|
||||||
|
console.warn("没有有效的 breaks 数据");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const styleConfig = layerStyleConfig.styleConfig;
|
||||||
|
|
||||||
|
if (!setContours) return;
|
||||||
|
|
||||||
|
const breaksLength = breaks.length;
|
||||||
|
// 根据 breaks 计算每个分段的颜色
|
||||||
|
const colors: string[] =
|
||||||
|
styleConfig.colorType === "single"
|
||||||
|
? // 单一色重复多次
|
||||||
|
Array.from({ length: breaksLength }, () => {
|
||||||
|
return SINGLE_COLOR_PALETTES[styleConfig.singlePaletteIndex].color;
|
||||||
|
})
|
||||||
|
: styleConfig.colorType === "gradient"
|
||||||
|
? generateGradientColors(breaksLength)
|
||||||
|
: styleConfig.colorType === "rainbow"
|
||||||
|
? generateRainbowColors(breaksLength)
|
||||||
|
: (() => {
|
||||||
|
// 自定义颜色
|
||||||
|
const custom = styleConfig.customColors || [];
|
||||||
|
// 如果自定义颜色数量不足,用反向彩虹色填充
|
||||||
|
const result = [...custom];
|
||||||
|
const reverseRainbowColors = RAINBOW_PALETTES[1].colors;
|
||||||
|
while (result.length < breaksLength) {
|
||||||
|
result.push(
|
||||||
|
reverseRainbowColors[
|
||||||
|
(result.length - custom.length) % reverseRainbowColors.length
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return result.slice(0, breaksLength);
|
||||||
|
})();
|
||||||
|
|
||||||
|
// 构造 ContourLayer 所需的 contours 配置
|
||||||
|
const contours = [];
|
||||||
|
for (let i = 0; i < breaks.length - 1; i++) {
|
||||||
|
const colorObj = parseColor(colors[i]);
|
||||||
|
contours.push({
|
||||||
|
threshold: [breaks[i], breaks[i + 1]],
|
||||||
|
color: [
|
||||||
|
colorObj.r,
|
||||||
|
colorObj.g,
|
||||||
|
colorObj.b,
|
||||||
|
Math.round(styleConfig.opacity * 255),
|
||||||
|
],
|
||||||
|
strokeWidth: 0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 应用样式到等值线图层
|
||||||
|
setContours(contours);
|
||||||
|
};
|
||||||
|
|
||||||
// 重置样式
|
// 重置样式
|
||||||
const resetStyle = useCallback(() => {
|
const resetStyle = useCallback(() => {
|
||||||
if (!selectedRenderLayer) return;
|
if (!selectedRenderLayer) return;
|
||||||
@@ -679,6 +742,7 @@ const StyleEditorPanel: React.FC<StyleEditorPanelProps> = ({
|
|||||||
setApplyJunctionStyle(false);
|
setApplyJunctionStyle(false);
|
||||||
if (setShowJunctionTextLayer) setShowJunctionTextLayer(false);
|
if (setShowJunctionTextLayer) setShowJunctionTextLayer(false);
|
||||||
if (setJunctionText) setJunctionText("");
|
if (setJunctionText) setJunctionText("");
|
||||||
|
setContours && setContours([]);
|
||||||
setContourLayerAvailable && setContourLayerAvailable(false);
|
setContourLayerAvailable && setContourLayerAvailable(false);
|
||||||
} else if (layerId === "pipes") {
|
} else if (layerId === "pipes") {
|
||||||
setApplyPipeStyle(false);
|
setApplyPipeStyle(false);
|
||||||
|
|||||||
@@ -62,7 +62,8 @@ interface DataContextType {
|
|||||||
pipeText: string;
|
pipeText: string;
|
||||||
setJunctionText?: React.Dispatch<React.SetStateAction<string>>;
|
setJunctionText?: React.Dispatch<React.SetStateAction<string>>;
|
||||||
setPipeText?: React.Dispatch<React.SetStateAction<string>>;
|
setPipeText?: React.Dispatch<React.SetStateAction<string>>;
|
||||||
deckLayer?: DeckLayer; // DeckLayer 实例
|
setContours?: React.Dispatch<React.SetStateAction<any[]>>;
|
||||||
|
deckLayer?: DeckLayer;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 跨组件传递
|
// 跨组件传递
|
||||||
@@ -122,6 +123,7 @@ const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
|
|||||||
const [showContourLayer, setShowContourLayer] = useState(false); // 控制等高线图层显示
|
const [showContourLayer, setShowContourLayer] = useState(false); // 控制等高线图层显示
|
||||||
const [junctionText, setJunctionText] = useState("pressure");
|
const [junctionText, setJunctionText] = useState("pressure");
|
||||||
const [pipeText, setPipeText] = useState("flow");
|
const [pipeText, setPipeText] = useState("flow");
|
||||||
|
const [contours, setContours] = useState<any[]>([]);
|
||||||
const flowAnimation = useRef(false); // 添加动画控制标志
|
const flowAnimation = useRef(false); // 添加动画控制标志
|
||||||
const [isContourLayerAvailable, setContourLayerAvailable] = useState(false); // 控制等高线图层显示
|
const [isContourLayerAvailable, setContourLayerAvailable] = useState(false); // 控制等高线图层显示
|
||||||
const [isWaterflowLayerAvailable, setWaterflowLayerAvailable] =
|
const [isWaterflowLayerAvailable, setWaterflowLayerAvailable] =
|
||||||
@@ -773,7 +775,6 @@ const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
|
|||||||
// outlineColor: [255, 255, 255, 220],
|
// outlineColor: [255, 255, 255, 220],
|
||||||
});
|
});
|
||||||
|
|
||||||
const ALPHA = 102;
|
|
||||||
const contourLayer = new ContourLayer({
|
const contourLayer = new ContourLayer({
|
||||||
id: "junctionContourLayer",
|
id: "junctionContourLayer",
|
||||||
name: "等值线",
|
name: "等值线",
|
||||||
@@ -781,15 +782,7 @@ const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
|
|||||||
aggregation: "MEAN",
|
aggregation: "MEAN",
|
||||||
cellSize: 600,
|
cellSize: 600,
|
||||||
strokeWidth: 0,
|
strokeWidth: 0,
|
||||||
contours: [
|
contours: contours,
|
||||||
// { threshold: [0, 16], color: [255, 0, 0, ALPHA], strokeWidth: 0 },
|
|
||||||
{ threshold: [16, 18], color: [255, 0, 0, 0], strokeWidth: 0 },
|
|
||||||
{ threshold: [18, 20], color: [255, 127, 0, ALPHA], strokeWidth: 0 },
|
|
||||||
{ threshold: [20, 22], color: [255, 215, 0, ALPHA], strokeWidth: 0 },
|
|
||||||
{ threshold: [22, 24], color: [199, 224, 0, ALPHA], strokeWidth: 0 },
|
|
||||||
{ threshold: [24, 26], color: [76, 175, 80, ALPHA], strokeWidth: 0 },
|
|
||||||
{ threshold: [26, 30], color: [63, 81, 181, ALPHA], strokeWidth: 0 },
|
|
||||||
],
|
|
||||||
getPosition: (d) => d.position,
|
getPosition: (d) => d.position,
|
||||||
getWeight: (d: any) =>
|
getWeight: (d: any) =>
|
||||||
(d[junctionText] as number) < 0 ? 0 : (d[junctionText] as number),
|
(d[junctionText] as number) < 0 ? 0 : (d[junctionText] as number),
|
||||||
@@ -821,7 +814,11 @@ const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
|
|||||||
showContourLayer,
|
showContourLayer,
|
||||||
junctionText,
|
junctionText,
|
||||||
pipeText,
|
pipeText,
|
||||||
|
contours,
|
||||||
]);
|
]);
|
||||||
|
useEffect(() => {
|
||||||
|
console.log("Contour Layer Available:", isContourLayerAvailable);
|
||||||
|
}, [isContourLayerAvailable]);
|
||||||
// 控制流动动画开关
|
// 控制流动动画开关
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (pipeText === "flow" && currentPipeCalData.length > 0) {
|
if (pipeText === "flow" && currentPipeCalData.length > 0) {
|
||||||
@@ -879,11 +876,11 @@ const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
|
|||||||
trailLength: 2, // 水流尾迹淡出时间
|
trailLength: 2, // 水流尾迹淡出时间
|
||||||
currentTime: currentTime,
|
currentTime: currentTime,
|
||||||
});
|
});
|
||||||
if (deckLayer.getDeckLayerById("waterflowLayer")) {
|
// if (deckLayer.getDeckLayerById("waterflowLayer")) {
|
||||||
deckLayer.updateDeckLayer("waterflowLayer", waterflowLayer);
|
// deckLayer.updateDeckLayer("waterflowLayer", waterflowLayer);
|
||||||
} else {
|
// } else {
|
||||||
deckLayer.addDeckLayer(waterflowLayer);
|
// deckLayer.addDeckLayer(waterflowLayer);
|
||||||
}
|
// }
|
||||||
// 继续请求动画帧,每帧执行一次函数
|
// 继续请求动画帧,每帧执行一次函数
|
||||||
animationFrameId = requestAnimationFrame(animate);
|
animationFrameId = requestAnimationFrame(animate);
|
||||||
};
|
};
|
||||||
@@ -917,41 +914,45 @@ const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
|
|||||||
const linkMap: Map<string, any> = new Map(
|
const linkMap: Map<string, any> = new Map(
|
||||||
currentPipeCalData.map((r: any) => [r.ID, r])
|
currentPipeCalData.map((r: any) => [r.ID, r])
|
||||||
);
|
);
|
||||||
|
if (nodeMap.size > 0) {
|
||||||
// 更新junctionData
|
// 更新junctionData
|
||||||
setJunctionDataState((prev: any[]) =>
|
setJunctionDataState((prev: any[]) =>
|
||||||
prev.map((j) => {
|
prev.map((j) => {
|
||||||
const record = nodeMap.get(j.id);
|
const record = nodeMap.get(j.id);
|
||||||
if (record) {
|
if (record) {
|
||||||
return {
|
return {
|
||||||
...j,
|
...j,
|
||||||
[junctionProperties]: record.value,
|
[junctionProperties]: record.value,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return j;
|
return j;
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
}
|
||||||
// 更新pipeData
|
if (linkMap.size > 0) {
|
||||||
setPipeDataState((prev: any[]) =>
|
// 更新pipeData
|
||||||
prev.map((p) => {
|
setPipeDataState((prev: any[]) =>
|
||||||
const record = linkMap.get(p.id);
|
prev.map((p) => {
|
||||||
if (record) {
|
const record = linkMap.get(p.id);
|
||||||
return {
|
if (record) {
|
||||||
...p,
|
return {
|
||||||
flowFlag: pipeProperties === "flow" && record.value < 0 ? -1 : 1,
|
...p,
|
||||||
path:
|
flowFlag: pipeProperties === "flow" && record.value < 0 ? -1 : 1,
|
||||||
pipeProperties === "flow" && record.value < 0 && p.flowFlag > 0
|
path:
|
||||||
? [...p.path].reverse()
|
pipeProperties === "flow" && record.value < 0 && p.flowFlag > 0
|
||||||
: p.path,
|
? [...p.path].reverse()
|
||||||
// 流量数值
|
: p.path,
|
||||||
[pipeProperties]:
|
// 流量数值
|
||||||
pipeProperties === "flow" ? Math.abs(record.value) : record.value,
|
[pipeProperties]:
|
||||||
};
|
pipeProperties === "flow"
|
||||||
}
|
? Math.abs(record.value)
|
||||||
return p;
|
: record.value,
|
||||||
})
|
};
|
||||||
);
|
}
|
||||||
|
return p;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
}, [currentJunctionCalData, currentPipeCalData]);
|
}, [currentJunctionCalData, currentPipeCalData]);
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -981,6 +982,7 @@ const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
|
|||||||
setPipeText,
|
setPipeText,
|
||||||
junctionText,
|
junctionText,
|
||||||
pipeText,
|
pipeText,
|
||||||
|
setContours,
|
||||||
deckLayer,
|
deckLayer,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -111,21 +111,6 @@ export class DeckLayer extends Layer {
|
|||||||
// 替换为新的 layer 实例
|
// 替换为新的 layer 实例
|
||||||
return layerOrProps;
|
return layerOrProps;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 否则假定传入的是 props 对象,使用现有 layer.clone(props) 创建新实例
|
|
||||||
try {
|
|
||||||
return layer.clone(layerOrProps);
|
|
||||||
} catch (err) {
|
|
||||||
// 如果 clone 失败,作为降级策略尝试手动复制 props 到新对象(保留原 layer)
|
|
||||||
// 这通常不应该发生,但保证不会抛出而破坏整个 layers 列表
|
|
||||||
const newLayer = layer.clone
|
|
||||||
? layer.clone(layerOrProps)
|
|
||||||
: {
|
|
||||||
...layer,
|
|
||||||
props: { ...(layer.props || {}), ...(layerOrProps || {}) },
|
|
||||||
};
|
|
||||||
return newLayer;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.deck.setProps({ layers: updatedLayers });
|
this.deck.setProps({ layers: updatedLayers });
|
||||||
|
|||||||
Reference in New Issue
Block a user