From 734851296d63c9a30315a1c8a0e29de12be64ce3 Mon Sep 17 00:00:00 2001 From: zihanjian Date: Sun, 25 May 2025 12:30:07 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=AE=8C=E6=95=B4=E8=89=B2?= =?UTF-8?q?=E6=9D=BF=E5=88=87=E6=8D=A2=E5=8A=9F=E8=83=BD=EF=BC=8C=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E9=A2=9C=E8=89=B2=E6=8E=92=E5=BA=8F=E9=80=BB=E8=BE=91?= =?UTF-8?q?=EF=BC=8C=E6=94=AF=E6=8C=81=E6=8C=89=E8=89=B2=E7=9B=B8=E6=8E=92?= =?UTF-8?q?=E5=BA=8F=EF=BC=8C=E6=9B=B4=E6=96=B0=E7=9B=B8=E5=85=B3=E7=BB=84?= =?UTF-8?q?=E4=BB=B6=E4=BB=A5=E6=8F=90=E5=8D=87=E7=94=A8=E6=88=B7=E4=BD=93?= =?UTF-8?q?=E9=AA=8C=E5=92=8C=E4=BB=A3=E7=A0=81=E5=8F=AF=E8=AF=BB=E6=80=A7?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/page.tsx | 46 ++++++--- src/components/ColorPalette.tsx | 168 ++++++++++++++++++++------------ src/utils/colorSystemUtils.ts | 58 +++++++++++ 3 files changed, 200 insertions(+), 72 deletions(-) diff --git a/src/app/page.tsx b/src/app/page.tsx index 4769281..701f629 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -25,6 +25,7 @@ import { convertPaletteToColorSystem, getColorKeyByHex, getMardToHexMapping, + sortColorsByHue, ColorSystem } from '../utils/colorSystemUtils'; @@ -144,6 +145,9 @@ export default function Home() { // 新增:高亮相关状态 const [highlightColorKey, setHighlightColorKey] = useState(null); + // 新增:完整色板切换状态 + const [showFullPalette, setShowFullPalette] = useState(false); + const originalCanvasRef = useRef(null); const pixelatedCanvasRef = useRef(null); const fileInputRef = useRef(null); @@ -196,23 +200,16 @@ export default function Home() { // 转换为数组并为每个hex值生成对应的色号系统显示 const originalColors = Array.from(uniqueColorsMap.values()); - return originalColors.map(color => { + const colorData = originalColors.map(color => { const displayKey = getColorKeyByHex(color.color.toUpperCase(), selectedColorSystem); return { key: displayKey, color: color.color }; - }).sort((a, b) => { - // 对显示的色号进行排序 - if (selectedColorSystem === 'MARD') { - return sortColorKeys(a.key, b.key); - } else { - // 对于数字色号系统,按数字排序 - const aNum = parseInt(a.key) || 0; - const bNum = parseInt(b.key) || 0; - return aNum - bNum; - } }); + + // 使用色相排序而不是色号排序 + return sortColorsByHue(colorData); }, [mappedPixelData, selectedColorSystem]); // 初始化时从本地存储加载自定义色板选择 @@ -1195,6 +1192,30 @@ export default function Home() { setHighlightColorKey(null); }; + // 新增:切换完整色板显示 + const handleToggleFullPalette = () => { + setShowFullPalette(!showFullPalette); + }; + + // 生成完整色板数据(用户自定义色板中选中的所有颜色) + const fullPaletteColors = useMemo(() => { + const selectedColors: { key: string; color: string }[] = []; + + Object.entries(customPaletteSelections).forEach(([hexValue, isSelected]) => { + if (isSelected) { + // 根据选择的色号系统获取显示的色号 + const displayKey = getColorKeyByHex(hexValue, selectedColorSystem); + selectedColors.push({ + key: displayKey, + color: hexValue + }); + } + }); + + // 使用色相排序而不是色号排序 + return sortColorsByHue(selectedColors); + }, [customPaletteSelections, selectedColorSystem]); + return ( <> {/* 添加自定义动画样式 */} @@ -1553,6 +1574,9 @@ export default function Home() { isEraseMode={isEraseMode} onEraseToggle={handleEraseToggle} onHighlightColor={handleHighlightColor} + fullPaletteColors={fullPaletteColors} + showFullPalette={showFullPalette} + onToggleFullPalette={handleToggleFullPalette} /> diff --git a/src/components/ColorPalette.tsx b/src/components/ColorPalette.tsx index 2afe4e4..5dcde29 100644 --- a/src/components/ColorPalette.tsx +++ b/src/components/ColorPalette.tsx @@ -21,6 +21,10 @@ interface ColorPaletteProps { onEraseToggle?: () => void; // 新增:高亮相关props onHighlightColor?: (colorHex: string) => void; // 触发高亮某个颜色 + // 新增:完整色板相关props + fullPaletteColors?: ColorData[]; // 用户自定义色板中的所有颜色 + showFullPalette?: boolean; // 是否显示完整色板 + onToggleFullPalette?: () => void; // 切换完整色板显示 } const ColorPalette: React.FC = ({ @@ -31,79 +35,121 @@ const ColorPalette: React.FC = ({ selectedColorSystem, isEraseMode, onEraseToggle, - onHighlightColor + onHighlightColor, + fullPaletteColors, + showFullPalette, + onToggleFullPalette }) => { if (!colors || colors.length === 0) { // Apply dark mode text color return

当前图纸无可用颜色。

; } + // 确定要显示的颜色集合 + // 如果显示完整色板,需要过滤掉透明颜色(因为完整色板不包含透明色) + const colorsToShow = showFullPalette && fullPaletteColors + ? [colors.find(c => transparentKey && c.key === transparentKey), ...fullPaletteColors].filter(Boolean) as ColorData[] + : colors; + return ( // Apply dark mode styles to the container -
- {/* 一键擦除按钮 */} - {onEraseToggle && ( - - )} - - {colors.map((colorData) => { - // 检查当前颜色是否是透明/橡皮擦 - const isTransparent = transparentKey && colorData.key === transparentKey; - const isSelected = selectedColor?.key === colorData.key; - - return ( +
+ {/* 色板切换按钮区域 */} + {fullPaletteColors && fullPaletteColors.length > 0 && onToggleFullPalette && ( +
- ); - })} +
+ )} + + {/* 颜色按钮区域 */} +
+ {/* 一键擦除按钮 */} + {onEraseToggle && ( + + )} + + {colorsToShow.map((colorData) => { + // 检查当前颜色是否是透明/橡皮擦 + const isTransparent = transparentKey && colorData.key === transparentKey; + const isSelected = selectedColor?.key === colorData.key; + + return ( + + ); + })} +
); }; diff --git a/src/utils/colorSystemUtils.ts b/src/utils/colorSystemUtils.ts index 6c02098..8147aba 100644 --- a/src/utils/colorSystemUtils.ts +++ b/src/utils/colorSystemUtils.ts @@ -115,4 +115,62 @@ export function getColorKeyByHex(hexValue: string, colorSystem: ColorSystem): st // 如果找不到映射,返回 '?' return '?'; +} + +// 将hex颜色转换为HSL +function hexToHsl(hex: string): { h: number; s: number; l: number } { + // 移除 # 符号 + const cleanHex = hex.replace('#', ''); + + // 转换为RGB + const r = parseInt(cleanHex.substring(0, 2), 16) / 255; + const g = parseInt(cleanHex.substring(2, 4), 16) / 255; + const b = parseInt(cleanHex.substring(4, 6), 16) / 255; + + const max = Math.max(r, g, b); + const min = Math.min(r, g, b); + const diff = max - min; + + let h = 0; + let s = 0; + const l = (max + min) / 2; + + if (diff !== 0) { + s = l > 0.5 ? diff / (2 - max - min) : diff / (max + min); + + switch (max) { + case r: + h = ((g - b) / diff + (g < b ? 6 : 0)) / 6; + break; + case g: + h = ((b - r) / diff + 2) / 6; + break; + case b: + h = ((r - g) / diff + 4) / 6; + break; + } + } + + return { h: h * 360, s: s * 100, l: l * 100 }; +} + +// 按色相排序颜色 +export function sortColorsByHue(colors: T[]): T[] { + return colors.slice().sort((a, b) => { + const hslA = hexToHsl(a.color); + const hslB = hexToHsl(b.color); + + // 首先按色相排序 + if (Math.abs(hslA.h - hslB.h) > 5) { // 增加色相容差,让更相近的色相归为一组 + return hslA.h - hslB.h; + } + + // 色相相近时,按明度排序(从浅到深) + if (Math.abs(hslA.l - hslB.l) > 3) { + return hslB.l - hslA.l; // 浅色(高明度)在前,深色(低明度)在后 + } + + // 明度也相近时,按饱和度排序(高饱和度在前,让鲜艳的颜色更突出) + return hslB.s - hslA.s; + }); } \ No newline at end of file