新增透明色功能,定义透明键并添加透明色数据,优化颜色选择逻辑以支持橡皮擦功能,同时更新调色板组件以显示透明选项,提升用户交互体验。

This commit is contained in:
Zylan
2025-04-25 16:08:29 +08:00
parent 8ef5e2fcbf
commit eca4ac044e
2 changed files with 98 additions and 28 deletions

View File

@@ -80,6 +80,12 @@ const fullBeadPalette: PaletteColor[] = Object.entries(beadPaletteData)
})
.filter((color): color is PaletteColor => color !== null);
// ++ 添加透明键定义 ++
const TRANSPARENT_KEY = 'ERASE';
// ++ 添加透明色数据 ++
const transparentColorData: MappedPixel = { key: TRANSPARENT_KEY, color: '#FFFFFF', isExternal: true };
// ++ Add definition for background color keys ++
const BACKGROUND_COLOR_KEYS = ['T1', 'H1', 'H2']; // 可以根据需要调整
@@ -1042,17 +1048,65 @@ export default function Home() {
const currentCell = newPixelData[j]?.[i]; // Get current cell data safely
// Check if the color needs changing OR if it was an external cell being colored
if (!currentCell || currentCell.key !== selectedColor.key || currentCell.isExternal) {
// ++ Apply selected color/key AND ensure isExternal is false ++
newPixelData[j][i] = { ...selectedColor, isExternal: false };
if (!currentCell) return; // Prevent invalid cells
const previousKey = currentCell.key;
const wasExternal = currentCell.isExternal;
// Determine new cell data
let newCellData: MappedPixel;
// Check if using eraser
if (selectedColor.key === TRANSPARENT_KEY) {
// Erasing: Mark as external
newCellData = { ...transparentColorData };
} else {
// Normal coloring: Apply selected color and mark as internal
newCellData = { ...selectedColor, isExternal: false };
}
// Only update if state actually changes
if (newCellData.key !== previousKey || newCellData.isExternal !== wasExternal) {
newPixelData[j][i] = newCellData;
setMappedPixelData(newPixelData);
// Explicitly redraw canvas immediately after state update
// Update color counts
if (colorCounts) {
const newColorCounts = { ...colorCounts };
let newTotalCount = totalBeadCount;
// If previous was internal bead, decrement its count
if (!wasExternal && previousKey !== TRANSPARENT_KEY && newColorCounts[previousKey]) {
newColorCounts[previousKey].count--;
if (newColorCounts[previousKey].count <= 0) {
delete newColorCounts[previousKey]; // Remove if count reaches zero
}
newTotalCount--;
}
// If new is internal bead, increment its count
if (!newCellData.isExternal && newCellData.key !== TRANSPARENT_KEY) {
if (!newColorCounts[newCellData.key]) {
const colorInfo = fullBeadPalette.find(p => p.key === newCellData.key);
newColorCounts[newCellData.key] = {
count: 0,
color: colorInfo?.hex || '#000000'
};
}
newColorCounts[newCellData.key].count++;
newTotalCount++;
}
setColorCounts(newColorCounts);
setTotalBeadCount(newTotalCount);
}
// Immediately redraw canvas
if (pixelatedCanvasRef.current) {
drawPixelatedCanvas(newPixelData, pixelatedCanvasRef, gridDimensions);
}
}
// After a click in manual mode, always clear the tooltip
// Clear tooltip after click
setTooltipData(null);
}
// Tooltip Logic (only show if NOT a manual coloring click)
@@ -1197,11 +1251,12 @@ export default function Home() {
</button>
{/* Color Palette (only in manual mode) */}
<div className="mt-3">
<p className="text-xs text-center text-gray-600 mb-2">:</p>
<p className="text-xs text-center text-gray-600 mb-2">:</p>
<ColorPalette
colors={currentGridColors}
colors={[transparentColorData, ...currentGridColors]}
selectedColor={selectedColor}
onColorSelect={setSelectedColor}
transparentKey={TRANSPARENT_KEY}
/>
</div>
</div>
@@ -1209,9 +1264,6 @@ export default function Home() {
{/* Canvas Preview Container */}
<div className="bg-white p-3 sm:p-4 rounded-lg shadow">
<h2 className="text-base sm:text-lg font-medium mb-3 sm:mb-4 text-center text-gray-800">
{isManualColoringMode ? "手动上色中... (点击格子填充)" : "图纸预览(悬停或长按查看颜色)"}
</h2>
<div className="flex justify-center mb-3 sm:mb-4 bg-gray-100 p-2 rounded overflow-hidden touch-none"
style={{ minHeight: '150px' }}>
<canvas

View File

@@ -6,38 +6,56 @@ import React from 'react';
interface ColorData {
key: string;
color: string;
isExternal?: boolean; // 添加 isExternal 属性以支持透明/橡皮擦功能
}
interface ColorPaletteProps {
colors: ColorData[];
selectedColor: ColorData | null;
onColorSelect: (colorData: ColorData) => void;
transparentKey?: string; // 添加可选参数,用于识别哪个是透明/橡皮擦
}
const ColorPalette: React.FC<ColorPaletteProps> = ({ colors, selectedColor, onColorSelect }) => {
const ColorPalette: React.FC<ColorPaletteProps> = ({
colors,
selectedColor,
onColorSelect,
transparentKey
}) => {
if (!colors || colors.length === 0) {
return <p className="text-xs text-center text-gray-500 py-2"></p>;
}
return (
<div className="flex flex-wrap justify-center gap-2 p-2 bg-white rounded border border-blue-200">
{colors.map((colorData) => (
<button
key={colorData.key}
onClick={() => onColorSelect(colorData)}
className={`w-8 h-8 rounded border-2 flex-shrink-0 transition-transform transform hover:scale-110 focus:outline-none focus:ring-2 focus:ring-offset-1 focus:ring-blue-400 ${
selectedColor?.key === colorData.key
? 'border-black ring-2 ring-offset-1 ring-blue-400 scale-110 shadow-md' // Enhanced selected style
: 'border-gray-300 hover:border-gray-500'
}`}
style={{ backgroundColor: colorData.color }}
title={`选择 ${colorData.key} (${colorData.color})`} // Add hex to title
aria-label={`选择颜色 ${colorData.key}`} // Accessibility
>
{/* Optional: Display key inside swatch if needed, adjust styles accordingly */}
{/* <span className="text-xs font-mono mix-blend-difference text-white">{colorData.key}</span> */}
</button>
))}
{colors.map((colorData) => {
// 检查当前颜色是否是透明/橡皮擦
const isTransparent = transparentKey && colorData.key === transparentKey;
return (
<button
key={colorData.key}
onClick={() => onColorSelect(colorData)}
className={`w-8 h-8 rounded border-2 flex-shrink-0 transition-transform transform hover:scale-110 focus:outline-none focus:ring-2 focus:ring-offset-1 focus:ring-blue-400 ${
selectedColor?.key === colorData.key
? 'border-black ring-2 ring-offset-1 ring-blue-400 scale-110 shadow-md' // Enhanced selected style
: 'border-gray-300 hover:border-gray-500'
} ${isTransparent ? 'flex items-center justify-center' : ''}`}
style={isTransparent ? {} : { backgroundColor: colorData.color }}
title={isTransparent
? '选择橡皮擦 (清除单元格)'
: `选择 ${colorData.key} (${colorData.color})`}
aria-label={isTransparent ? '选择橡皮擦' : `选择颜色 ${colorData.key}`}
>
{/* 如果是透明/橡皮擦按钮,显示叉号图标 */}
{isTransparent && (
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5 text-gray-500" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
<path strokeLinecap="round" strokeLinejoin="round" d="M6 18L18 6M6 6l12 12" />
</svg>
)}
</button>
);
})}
</div>
);
};