修复离散彩虹颜色显示问题

This commit is contained in:
JIANG
2025-11-18 11:58:32 +08:00
parent 01563c3c2d
commit 9c533c0911
3 changed files with 995 additions and 82 deletions

View File

@@ -233,21 +233,11 @@ const StyleEditorPanel: React.FC<StyleEditorPanelProps> = ({
(segments: number): string[] => {
const baseColors =
RAINBOW_PALETTES[styleConfig.rainbowPaletteIndex].colors;
if (segments <= baseColors.length) {
// 如果分段数小于等于基础颜色数,均匀选取
const step = baseColors.length / segments;
return Array.from(
{ length: segments },
(_, i) => baseColors[Math.floor(i * step)]
);
} else {
// 如果分段数大于基础颜色数,重复使用
return Array.from(
{ length: segments },
(_, i) => baseColors[i % baseColors.length]
);
}
// 严格按顺序返回 N 个颜色
return Array.from(
{ length: segments },
(_, i) => baseColors[i % baseColors.length]
);
},
[styleConfig.rainbowPaletteIndex]
);
@@ -954,6 +944,25 @@ const StyleEditorPanel: React.FC<StyleEditorPanelProps> = ({
}
>
{GRADIENT_PALETTES.map((p, idx) => {
const numColors = styleConfig.segments + 1;
const previewColors = Array.from(
{ length: numColors },
(_, i) => {
const ratio = numColors > 1 ? i / (numColors - 1) : 1;
const startColor = parseColor(p.start);
const endColor = parseColor(p.end);
const r = Math.round(
startColor.r + (endColor.r - startColor.r) * ratio
);
const g = Math.round(
startColor.g + (endColor.g - startColor.g) * ratio
);
const b = Math.round(
startColor.b + (endColor.b - startColor.b) * ratio
);
return `rgba(${r}, ${g}, ${b}, 1)`;
}
);
return (
<MenuItem key={idx} value={idx}>
<Box
@@ -965,11 +974,22 @@ const StyleEditorPanel: React.FC<StyleEditorPanelProps> = ({
width: "80%",
height: 16,
borderRadius: 2,
background: `linear-gradient(90deg, ${p.start}, ${p.end})`,
display: "flex",
overflow: "hidden",
marginRight: 1,
border: "1px solid #ccc",
}}
/>
>
{previewColors.map((color, colorIdx) => (
<Box
key={colorIdx}
sx={{
flex: 1,
backgroundColor: color,
}}
/>
))}
</Box>
</Box>
</MenuItem>
);
@@ -997,23 +1017,13 @@ const StyleEditorPanel: React.FC<StyleEditorPanelProps> = ({
}
>
{RAINBOW_PALETTES.map((p, idx) => {
// 根据当前分段数生成该方案的预览颜色
// 根据当前分段数+1生成该方案的预览颜色
const baseColors = p.colors;
const segments = styleConfig.segments;
let previewColors: string[];
if (segments <= baseColors.length) {
const step = baseColors.length / segments;
previewColors = Array.from(
{ length: segments },
(_, i) => baseColors[Math.floor(i * step)]
);
} else {
previewColors = Array.from(
{ length: segments },
(_, i) => baseColors[i % baseColors.length]
);
}
const numColors = styleConfig.segments + 1;
const previewColors = Array.from(
{ length: numColors },
(_, i) => baseColors[i % baseColors.length]
);
return (
<MenuItem key={idx} value={idx}>
@@ -1356,54 +1366,48 @@ const StyleEditorPanel: React.FC<StyleEditorPanelProps> = ({
{styleConfig.classificationMethod === "custom_breaks" && (
<Box className="mt-3 p-2 bg-gray-50 rounded">
<Typography variant="subtitle2" gutterBottom>
&gt;= 0
{">="} 0
</Typography>
<Box className="flex flex-col gap-2">
{Array.from({ length: styleConfig.segments + 1 }).map(
(_, idx) => (
<TextField
key={idx}
label={`阈值 ${idx + 1}`}
type="number"
size="small"
slotProps={{ input: { inputProps: { min: 0, step: 0.1 } } }}
value={
(styleConfig.customBreaks &&
styleConfig.customBreaks[idx]) ??
""
}
onChange={(e) => {
const v = parseFloat(e.target.value);
setStyleConfig((prev) => {
const prevBreaks = prev.customBreaks
? [...prev.customBreaks]
: [];
// 保证长度
while (prevBreaks.length < styleConfig.segments + 1)
prevBreaks.push(0);
prevBreaks[idx] = isNaN(v) ? 0 : Math.max(0, v);
return { ...prev, customBreaks: prevBreaks };
});
}}
onBlur={() => {
// on blur 保证升序
setStyleConfig((prev) => {
const prevBreaks = (prev.customBreaks || []).slice(
0,
styleConfig.segments + 1
);
prevBreaks.sort((a, b) => a - b);
return { ...prev, customBreaks: prevBreaks };
});
}}
/>
)
)}
{Array.from({ length: styleConfig.segments }).map((_, idx) => (
<TextField
key={idx}
label={`阈值 ${idx + 1}`}
type="number"
size="small"
slotProps={{ input: { inputProps: { min: 0, step: 0.1 } } }}
value={
(styleConfig.customBreaks &&
styleConfig.customBreaks[idx]) ??
""
}
onChange={(e) => {
const v = parseFloat(e.target.value);
setStyleConfig((prev) => {
const prevBreaks = prev.customBreaks
? [...prev.customBreaks]
: [];
// 保证长度
while (prevBreaks.length < styleConfig.segments + 1)
prevBreaks.push(0);
prevBreaks[idx] = isNaN(v) ? 0 : Math.max(0, v);
return { ...prev, customBreaks: prevBreaks };
});
}}
onBlur={() => {
// on blur 保证升序
setStyleConfig((prev) => {
const prevBreaks = (prev.customBreaks || []).slice(
0,
styleConfig.segments + 1
);
prevBreaks.sort((a, b) => a - b);
return { ...prev, customBreaks: prevBreaks };
});
}}
/>
))}
</Box>
<Typography variant="caption" color="textSecondary">
: 阈值数量由分类数量决定 (segments + 1) segments=5
6
</Typography>
</Box>
)}
{/* 颜色方案 */}