修复离散彩虹颜色显示问题
This commit is contained in:
@@ -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>
|
||||
手动设置区间阈值(按升序填写,最小值 >= 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>
|
||||
)}
|
||||
{/* 颜色方案 */}
|
||||
|
||||
Reference in New Issue
Block a user