新增自定义颜色方案
This commit is contained in:
@@ -49,6 +49,7 @@ interface StyleConfig {
|
|||||||
opacity: number;
|
opacity: number;
|
||||||
adjustWidthByProperty: boolean; // 是否根据属性调整线条宽度
|
adjustWidthByProperty: boolean; // 是否根据属性调整线条宽度
|
||||||
customBreaks?: number[]; // 自定义断点(用于 custom_breaks)
|
customBreaks?: number[]; // 自定义断点(用于 custom_breaks)
|
||||||
|
customColors?: string[]; // 自定义颜色(用于 colorType="custom")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 图层样式状态接口
|
// 图层样式状态接口
|
||||||
@@ -149,6 +150,29 @@ const CLASSIFICATION_METHODS = [
|
|||||||
{ name: "自定义", value: "custom_breaks" },
|
{ name: "自定义", value: "custom_breaks" },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const rgbaToHex = (rgba: string) => {
|
||||||
|
try {
|
||||||
|
const c = parseColor(rgba);
|
||||||
|
const toHex = (n: number) => {
|
||||||
|
const hex = Math.round(n).toString(16);
|
||||||
|
return hex.length === 1 ? "0" + hex : hex;
|
||||||
|
};
|
||||||
|
return `#${toHex(c.r)}${toHex(c.g)}${toHex(c.b)}`;
|
||||||
|
} catch (e) {
|
||||||
|
return "#000000";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const hexToRgba = (hex: string) => {
|
||||||
|
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
||||||
|
return result
|
||||||
|
? `rgba(${parseInt(result[1], 16)}, ${parseInt(result[2], 16)}, ${parseInt(
|
||||||
|
result[3],
|
||||||
|
16
|
||||||
|
)}, 1)`
|
||||||
|
: "rgba(0, 0, 0, 1)";
|
||||||
|
};
|
||||||
|
|
||||||
const StyleEditorPanel: React.FC<StyleEditorPanelProps> = ({
|
const StyleEditorPanel: React.FC<StyleEditorPanelProps> = ({
|
||||||
layerStyleStates,
|
layerStyleStates,
|
||||||
setLayerStyleStates,
|
setLayerStyleStates,
|
||||||
@@ -199,6 +223,7 @@ const StyleEditorPanel: React.FC<StyleEditorPanelProps> = ({
|
|||||||
opacity: 0.9,
|
opacity: 0.9,
|
||||||
adjustWidthByProperty: true,
|
adjustWidthByProperty: true,
|
||||||
customBreaks: [],
|
customBreaks: [],
|
||||||
|
customColors: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
// 根据分段数生成相应数量的渐进颜色
|
// 根据分段数生成相应数量的渐进颜色
|
||||||
@@ -467,7 +492,18 @@ const StyleEditorPanel: React.FC<StyleEditorPanelProps> = ({
|
|||||||
})
|
})
|
||||||
: styleConfig.colorType === "gradient"
|
: styleConfig.colorType === "gradient"
|
||||||
? generateGradientColors(breaksLength)
|
? generateGradientColors(breaksLength)
|
||||||
: generateRainbowColors(breaksLength);
|
: styleConfig.colorType === "rainbow"
|
||||||
|
? generateRainbowColors(breaksLength)
|
||||||
|
: (() => {
|
||||||
|
// 自定义颜色
|
||||||
|
const custom = styleConfig.customColors || [];
|
||||||
|
// 如果自定义颜色数量不足,用默认颜色补齐(这里简单用红色,或者重复最后一个)
|
||||||
|
const result = [...custom];
|
||||||
|
while (result.length < breaksLength) {
|
||||||
|
result.push(result[result.length - 1] || "rgba(255, 0, 0, 1)");
|
||||||
|
}
|
||||||
|
return result.slice(0, breaksLength);
|
||||||
|
})();
|
||||||
// 计算每个分段的线条粗细和点大小
|
// 计算每个分段的线条粗细和点大小
|
||||||
const dimensions: number[] =
|
const dimensions: number[] =
|
||||||
layerType === "linestring"
|
layerType === "linestring"
|
||||||
@@ -889,6 +925,22 @@ const StyleEditorPanel: React.FC<StyleEditorPanelProps> = ({
|
|||||||
currentPipeCalData,
|
currentPipeCalData,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
// 初始化或调整自定义颜色数组长度
|
||||||
|
useEffect(() => {
|
||||||
|
const numColors = styleConfig.segments;
|
||||||
|
setStyleConfig((prev) => {
|
||||||
|
const prevColors = prev.customColors || [];
|
||||||
|
if (prevColors.length === numColors) return prev;
|
||||||
|
|
||||||
|
const newColors = [...prevColors];
|
||||||
|
const baseColors = RAINBOW_PALETTES[0].colors;
|
||||||
|
while (newColors.length < numColors) {
|
||||||
|
newColors.push(baseColors[newColors.length % baseColors.length]);
|
||||||
|
}
|
||||||
|
return { ...prev, customColors: newColors.slice(0, numColors) };
|
||||||
|
});
|
||||||
|
}, [styleConfig.segments]);
|
||||||
|
|
||||||
const getColorSetting = () => {
|
const getColorSetting = () => {
|
||||||
if (styleConfig.colorType === "single") {
|
if (styleConfig.colorType === "single") {
|
||||||
return (
|
return (
|
||||||
@@ -1069,6 +1121,54 @@ const StyleEditorPanel: React.FC<StyleEditorPanelProps> = ({
|
|||||||
</FormControl>
|
</FormControl>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if (styleConfig.colorType === "custom") {
|
||||||
|
return (
|
||||||
|
<Box className="mt-3">
|
||||||
|
<Typography variant="subtitle2" gutterBottom>
|
||||||
|
自定义颜色
|
||||||
|
</Typography>
|
||||||
|
<Box
|
||||||
|
className="flex flex-col gap-2"
|
||||||
|
sx={{ maxHeight: "160px", overflowY: "auto", paddingTop: "4px" }}
|
||||||
|
>
|
||||||
|
{Array.from({ length: styleConfig.segments }).map((_, idx) => {
|
||||||
|
const color =
|
||||||
|
(styleConfig.customColors && styleConfig.customColors[idx]) ||
|
||||||
|
"rgba(0,0,0,1)";
|
||||||
|
return (
|
||||||
|
<Box key={idx} className="flex items-center gap-2">
|
||||||
|
<Typography variant="caption" sx={{ width: 40 }}>
|
||||||
|
分段{idx + 1}
|
||||||
|
</Typography>
|
||||||
|
<input
|
||||||
|
type="color"
|
||||||
|
value={rgbaToHex(color)}
|
||||||
|
onChange={(e) => {
|
||||||
|
const hex = e.target.value;
|
||||||
|
const newColor = hexToRgba(hex);
|
||||||
|
setStyleConfig((prev) => {
|
||||||
|
const newColors = [...(prev.customColors || [])];
|
||||||
|
while (newColors.length < styleConfig.segments)
|
||||||
|
newColors.push("rgba(0,0,0,1)");
|
||||||
|
newColors[idx] = newColor;
|
||||||
|
return { ...prev, customColors: newColors };
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
style={{
|
||||||
|
width: "100%",
|
||||||
|
height: "32px",
|
||||||
|
cursor: "pointer",
|
||||||
|
border: "1px solid #ccc",
|
||||||
|
borderRadius: "4px",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
// 根据不同图层的类型和颜色分类方案显示不同的大小设置
|
// 根据不同图层的类型和颜色分类方案显示不同的大小设置
|
||||||
const getSizeSetting = () => {
|
const getSizeSetting = () => {
|
||||||
@@ -1084,6 +1184,12 @@ const StyleEditorPanel: React.FC<StyleEditorPanelProps> = ({
|
|||||||
const rainbowColors =
|
const rainbowColors =
|
||||||
RAINBOW_PALETTES[styleConfig.rainbowPaletteIndex].colors;
|
RAINBOW_PALETTES[styleConfig.rainbowPaletteIndex].colors;
|
||||||
colors = [rainbowColors[0], rainbowColors[rainbowColors.length - 1]];
|
colors = [rainbowColors[0], rainbowColors[rainbowColors.length - 1]];
|
||||||
|
} else if (styleConfig.colorType === "custom") {
|
||||||
|
const customColors = styleConfig.customColors || [];
|
||||||
|
colors = [
|
||||||
|
customColors[0] || "rgba(0,0,0,1)",
|
||||||
|
customColors[customColors.length - 1] || "rgba(0,0,0,1)",
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selectedRenderLayer?.get("type") === "point") {
|
if (selectedRenderLayer?.get("type") === "point") {
|
||||||
@@ -1362,7 +1468,21 @@ const StyleEditorPanel: React.FC<StyleEditorPanelProps> = ({
|
|||||||
<Slider
|
<Slider
|
||||||
value={styleConfig.segments}
|
value={styleConfig.segments}
|
||||||
onChange={(_, value) =>
|
onChange={(_, value) =>
|
||||||
setStyleConfig((prev) => ({ ...prev, segments: value as number }))
|
setStyleConfig((prev) => {
|
||||||
|
const newSegments = value as number;
|
||||||
|
const newCustomColors = [...(prev.customColors || [])];
|
||||||
|
if (newSegments > newCustomColors.length) {
|
||||||
|
const baseColors = RAINBOW_PALETTES[0].colors;
|
||||||
|
for (let i = newCustomColors.length; i < newSegments; i++) {
|
||||||
|
newCustomColors.push(baseColors[i % baseColors.length]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
...prev,
|
||||||
|
segments: newSegments,
|
||||||
|
customColors: newCustomColors,
|
||||||
|
};
|
||||||
|
})
|
||||||
}
|
}
|
||||||
min={2}
|
min={2}
|
||||||
max={10}
|
max={10}
|
||||||
@@ -1379,7 +1499,7 @@ const StyleEditorPanel: React.FC<StyleEditorPanelProps> = ({
|
|||||||
</Typography>
|
</Typography>
|
||||||
<Box
|
<Box
|
||||||
className="flex flex-col gap-2"
|
className="flex flex-col gap-2"
|
||||||
sx={{ maxHeight: "240px", overflowY: "auto", paddingTop: "12px" }}
|
sx={{ maxHeight: "160px", overflowY: "auto", paddingTop: "12px" }}
|
||||||
>
|
>
|
||||||
{Array.from({ length: styleConfig.segments }).map((_, idx) => (
|
{Array.from({ length: styleConfig.segments }).map((_, idx) => (
|
||||||
<TextField
|
<TextField
|
||||||
@@ -1400,7 +1520,7 @@ const StyleEditorPanel: React.FC<StyleEditorPanelProps> = ({
|
|||||||
? [...prev.customBreaks]
|
? [...prev.customBreaks]
|
||||||
: [];
|
: [];
|
||||||
// 保证长度
|
// 保证长度
|
||||||
while (prevBreaks.length < styleConfig.segments + 1)
|
while (prevBreaks.length < styleConfig.segments)
|
||||||
prevBreaks.push(0);
|
prevBreaks.push(0);
|
||||||
prevBreaks[idx] = isNaN(v) ? 0 : Math.max(0, v);
|
prevBreaks[idx] = isNaN(v) ? 0 : Math.max(0, v);
|
||||||
return { ...prev, customBreaks: prevBreaks };
|
return { ...prev, customBreaks: prevBreaks };
|
||||||
@@ -1430,16 +1550,32 @@ const StyleEditorPanel: React.FC<StyleEditorPanelProps> = ({
|
|||||||
</InputLabel>
|
</InputLabel>
|
||||||
<Select
|
<Select
|
||||||
value={styleConfig.colorType}
|
value={styleConfig.colorType}
|
||||||
onChange={(e) =>
|
onChange={(e) => {
|
||||||
setStyleConfig((prev) => ({
|
const newColorType = e.target.value;
|
||||||
...prev,
|
setStyleConfig((prev) => {
|
||||||
colorType: e.target.value as "single" | "gradient" | "rainbow",
|
let newCustomColors = prev.customColors;
|
||||||
}))
|
if (
|
||||||
|
newColorType === "custom" &&
|
||||||
|
(!prev.customColors || prev.customColors.length === 0)
|
||||||
|
) {
|
||||||
|
const baseColors = RAINBOW_PALETTES[0].colors;
|
||||||
|
newCustomColors = Array.from(
|
||||||
|
{ length: prev.segments },
|
||||||
|
(_, i) => baseColors[i % baseColors.length]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
return {
|
||||||
|
...prev,
|
||||||
|
colorType: newColorType,
|
||||||
|
customColors: newCustomColors,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<MenuItem value="single">单一色</MenuItem>
|
<MenuItem value="single">单一色</MenuItem>
|
||||||
<MenuItem value="gradient">渐进色</MenuItem>
|
<MenuItem value="gradient">渐进色</MenuItem>
|
||||||
<MenuItem value="rainbow">离散彩虹</MenuItem>
|
<MenuItem value="rainbow">离散彩虹</MenuItem>
|
||||||
|
<MenuItem value="custom">自定义</MenuItem>
|
||||||
</Select>
|
</Select>
|
||||||
{getColorSetting()}
|
{getColorSetting()}
|
||||||
</FormControl>
|
</FormControl>
|
||||||
|
|||||||
@@ -666,10 +666,11 @@ const MapComponent: React.FC<MapComponentProps> = ({ children }) => {
|
|||||||
layers: [],
|
layers: [],
|
||||||
});
|
});
|
||||||
deckFlowRef.current = deckFlow;
|
deckFlowRef.current = deckFlow;
|
||||||
const deckFlowLayer = new DeckLayer(deckFlow);
|
const deckFlowLayer = new DeckLayer(deckFlow, {
|
||||||
deckFlowLayer.set("name", "水流动画");
|
name: "水流动画",
|
||||||
deckFlowLayer.set("value", "waterflow");
|
value: "waterflow",
|
||||||
deckFlowLayer.set("type", "animation");
|
type: "animation",
|
||||||
|
});
|
||||||
// 初始化用户可见性状态(默认为 true)
|
// 初始化用户可见性状态(默认为 true)
|
||||||
deckFlowLayer.initUserVisibility("waterflowLayer", true);
|
deckFlowLayer.initUserVisibility("waterflowLayer", true);
|
||||||
// 设置可见性变化回调,同步更新 waterflowUserVisible
|
// 设置可见性变化回调,同步更新 waterflowUserVisible
|
||||||
|
|||||||
@@ -11,9 +11,18 @@ export class DeckLayer extends Layer {
|
|||||||
private onVisibilityChange?: (layerId: string, visible: boolean) => void;
|
private onVisibilityChange?: (layerId: string, visible: boolean) => void;
|
||||||
private userVisibility: Map<string, boolean> = new Map(); // 存储用户设置的可见性
|
private userVisibility: Map<string, boolean> = new Map(); // 存储用户设置的可见性
|
||||||
|
|
||||||
constructor(deckInstance: Deck) {
|
/**
|
||||||
super({});
|
* @param deckInstance deck.gl 实例
|
||||||
|
* @param layerProperties 可选:在构造时直接设置到 OpenLayers Layer 的 properties
|
||||||
|
*/
|
||||||
|
constructor(deckInstance: Deck, layerProperties?: Record<string, any>) {
|
||||||
|
// 将 layerProperties 作为 Layer 的 properties 传入
|
||||||
|
super({ properties: layerProperties || {} });
|
||||||
this.deck = deckInstance;
|
this.deck = deckInstance;
|
||||||
|
// 再次确保属性应用到实例(兼容场景)
|
||||||
|
if (layerProperties) {
|
||||||
|
this.setProperties(layerProperties);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置可见性变化回调
|
// 设置可见性变化回调
|
||||||
@@ -118,4 +127,9 @@ export class DeckLayer extends Layer {
|
|||||||
this.setDeckLayerVisible(layerId, !currentVisible);
|
this.setDeckLayerVisible(layerId, !currentVisible);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 可选的封装:在外部用更语义化的方式设置属性(内部可直接调用 setProperties)
|
||||||
|
setLayerProperties(props: Record<string, any>): void {
|
||||||
|
this.setProperties(props);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user