Fix undefined variable references in ImageCanvas

ROOT CAUSE: ImageCanvas referenced props that don't exist:
- activeTool, onSmartSelect, onColorSelect were used but never declared
- selectionMode checked for 'smart'/'color' but App passes advancedToolMode with 'smart-select'/'color-select'

Changes:
- Update mode checking to use advancedToolMode instead of selectionMode for smart/color select
- Replace onSmartSelect/onColorSelect calls with onAdvancedToolClick
- Fix useEffect dependency array to reference actual props
- Add missing state/refs: currentZoom, imageRef, baseScaleRef, isDrawingRef
- Add zoom control buttons to canvas UI
- Fix tool mode indicator to check advancedToolMode
This commit is contained in:
Claude
2026-01-26 13:39:24 +00:00
parent c12e8c9508
commit 487f52a616
2 changed files with 81 additions and 25 deletions
+16 -7
View File
@@ -16,14 +16,27 @@
display: block; display: block;
} }
.clear-selection-btn { .canvas-controls {
position: absolute; position: absolute;
top: 10px; bottom: 10px;
left: 10px;
right: 10px; right: 10px;
display: flex;
justify-content: space-between;
align-items: center;
z-index: 10;
pointer-events: none;
}
.canvas-controls > * {
pointer-events: auto;
}
.clear-selection-btn {
background-color: #ff4444; background-color: #ff4444;
color: white; color: white;
padding: 8px 16px; padding: 8px 16px;
z-index: 10; border-radius: 4px;
} }
.clear-selection-btn:hover { .clear-selection-btn:hover {
@@ -46,16 +59,12 @@
/* Zoom controls */ /* Zoom controls */
.zoom-controls { .zoom-controls {
position: absolute;
bottom: 10px;
right: 10px;
display: flex; display: flex;
align-items: center; align-items: center;
gap: 4px; gap: 4px;
background-color: rgba(0, 0, 0, 0.8); background-color: rgba(0, 0, 0, 0.8);
padding: 6px 10px; padding: 6px 10px;
border-radius: 4px; border-radius: 4px;
z-index: 10;
} }
.zoom-controls button { .zoom-controls button {
+65 -18
View File
@@ -6,18 +6,23 @@ const ImageCanvas = forwardRef(({
imageUrl, imageUrl,
onSelectionChange, onSelectionChange,
selectionMode, selectionMode,
activeTool, advancedToolMode,
onAdvancedToolClick,
zoom = 100, zoom = 100,
onZoomChange, onZoomChange,
onSmartSelect, externalSelection,
isProcessing isProcessing
}, ref) => { }, ref) => {
const canvasRef = useRef(null); const canvasRef = useRef(null);
const fabricCanvasRef = useRef(null); const fabricCanvasRef = useRef(null);
const [currentSelection, setCurrentSelection] = useState(null); const [currentSelection, setCurrentSelection] = useState(null);
const [currentZoom, setCurrentZoom] = useState(1);
const currentSelectionRef = useRef(null); const currentSelectionRef = useRef(null);
const lassoPoints = useRef([]); const lassoPoints = useRef([]);
const onZoomChangeRef = useRef(onZoomChange); const onZoomChangeRef = useRef(onZoomChange);
const imageRef = useRef(null);
const baseScaleRef = useRef(1);
const isDrawingRef = useRef(false);
// Keep ref updated // Keep ref updated
useEffect(() => { useEffect(() => {
@@ -201,23 +206,23 @@ const ImageCanvas = forwardRef(({
canvas.off('object:moving'); canvas.off('object:moving');
canvas.off('object:scaling'); canvas.off('object:scaling');
// Set up handlers based on selection mode // Set up handlers based on selection mode or advanced tool mode
if (selectionMode === 'rectangle') { if (advancedToolMode === 'smart-select') {
setupSmartSelectMode(canvas);
} else if (advancedToolMode === 'color-select') {
setupColorSelectMode(canvas);
} else if (selectionMode === 'rectangle') {
setupRectangleMode(canvas); setupRectangleMode(canvas);
} else if (selectionMode === 'ellipse') { } else if (selectionMode === 'ellipse') {
setupEllipseMode(canvas); setupEllipseMode(canvas);
} else if (selectionMode === 'lasso') { } else if (selectionMode === 'lasso') {
setupLassoMode(canvas); setupLassoMode(canvas);
} else if (selectionMode === 'smart') { } else if (selectionMode === 'move') {
setupSmartSelectMode(canvas);
} else if (selectionMode === 'color') {
setupColorSelectMode(canvas);
} else if (activeTool === 'move') {
setupMoveMode(canvas); setupMoveMode(canvas);
} else if (activeTool === 'pan') { } else if (selectionMode === 'pan') {
setupPanMode(canvas); setupPanMode(canvas);
} }
}, [selectionMode, activeTool, onSmartSelect]); }, [selectionMode, advancedToolMode, onAdvancedToolClick, isProcessing]);
const setupMoveMode = (canvas) => { const setupMoveMode = (canvas) => {
// In move mode, allow selecting and moving selection objects // In move mode, allow selecting and moving selection objects
@@ -284,7 +289,7 @@ const ImageCanvas = forwardRef(({
// Check if click is within image bounds // Check if click is within image bounds
if (x >= 0 && x < img.width && y >= 0 && y < img.height) { if (x >= 0 && x < img.width && y >= 0 && y < img.height) {
onSmartSelect?.(x, y); onAdvancedToolClick?.(x, y, null);
} }
}); });
@@ -295,9 +300,38 @@ const ImageCanvas = forwardRef(({
canvas.on('mouse:down', (e) => { canvas.on('mouse:down', (e) => {
if (isProcessing) return; if (isProcessing) return;
// TODO: Get pixel color at click position
const pointer = canvas.getPointer(e.e); const pointer = canvas.getPointer(e.e);
console.log('Color select at:', pointer); const img = imageRef.current;
if (!img) return;
// Convert to image coordinates
const imgScale = img.scaleX;
const imgLeft = img.left;
const imgTop = img.top;
const x = Math.round((pointer.x - imgLeft) / imgScale);
const y = Math.round((pointer.y - imgTop) / imgScale);
// Check if click is within image bounds
if (x >= 0 && x < img.width && y >= 0 && y < img.height) {
// Get pixel color from canvas
const ctx = canvas.getContext('2d');
if (ctx) {
// Calculate actual canvas position accounting for viewport transform
const vpt = canvas.viewportTransform;
const canvasX = pointer.x * vpt[0] + vpt[4];
const canvasY = pointer.y * vpt[3] + vpt[5];
const pixelData = ctx.getImageData(canvasX, canvasY, 1, 1).data;
const color = {
r: pixelData[0],
g: pixelData[1],
b: pixelData[2]
};
onAdvancedToolClick?.(x, y, color);
}
}
}); });
canvas.setCursor('crosshair'); canvas.setCursor('crosshair');
@@ -691,10 +725,23 @@ const ImageCanvas = forwardRef(({
return ( return (
<div className="canvas-container"> <div className="canvas-container">
<canvas ref={canvasRef} /> <canvas ref={canvasRef} />
{currentSelection && ( <div className="canvas-controls">
<button className="clear-selection-btn" onClick={clearSelection}> <div className="zoom-controls">
Clear <button onClick={handleZoomOut} title="Zoom Out"></button>
</button> <span className="zoom-level">{Math.round(currentZoom * 100)}%</span>
<button onClick={handleZoomIn} title="Zoom In">+</button>
<button onClick={handleZoomReset} title="Reset Zoom"></button>
</div>
{currentSelection && (
<button className="clear-selection-btn" onClick={clearSelection}>
Clear Selection
</button>
)}
</div>
{(advancedToolMode === 'smart-select' || advancedToolMode === 'color-select') && (
<div className="tool-mode-indicator">
{advancedToolMode === 'smart-select' ? 'Click on an object to select it' : 'Click on a color to select similar pixels'}
</div>
)} )}
</div> </div>
); );