Kar l5win 2025-07-07 23:41:48 -07:00
parent a6ba03cb47
commit 84ee8cfaec
1 changed files with 88 additions and 58 deletions

View File

@ -1,59 +1,81 @@
import React, { useRef, useState, useEffect } from 'react'; import React, { useRef, useState, useEffect } from 'react';
import { ChromePicker } from 'react-color'; import { ChromePicker } from 'react-color';
const DrawingCanvas = ({ color, setColor, thickness, setThickness, history, setHistory }) => { // Drawing utilities
const drawLine = (ctx, x1, y1, x2, y2, color, thickness) => {
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.strokeStyle = color || '#000000';
ctx.lineWidth = thickness || 2;
ctx.lineCap = 'round';
ctx.stroke();
};
const drawShape = (ctx, shape) => {
ctx.beginPath();
ctx.strokeStyle = shape.color || '#000000';
ctx.lineWidth = shape.thickness || 2;
ctx.lineCap = 'round';
if (shape.type === 'rectangle') {
ctx.rect(shape.x || 0, shape.y || 0, shape.width || 0, shape.height || 0);
} else if (shape.type === 'circle') {
ctx.arc(shape.x || 0, shape.y || 0, shape.radius || 0, 0, Math.PI * 2);
}
ctx.stroke();
};
const DrawingCanvas = () => {
const canvasRef = useRef(null); const canvasRef = useRef(null);
const [isDrawing, setIsDrawing] = useState(false); const [isDrawing, setIsDrawing] = useState(false);
const [currentTool, setCurrentTool] = useState('pencil'); const [currentTool, setCurrentTool] = useState('pencil');
const [color, setColor] = useState('#000000');
const [thickness, setThickness] = useState(2);
const [history, setHistory] = useState([]);
const [shapes, setShapes] = useState([]); const [shapes, setShapes] = useState([]);
const [lastPosition, setLastPosition] = useState(null); const [lastPosition, setLastPosition] = useState(null);
const [undoHistory, setUndoHistory] = useState([]);
useEffect(() => { useEffect(() => {
const canvas = canvasRef.current; const canvas = canvasRef.current;
if (!canvas) return;
const ctx = canvas.getContext('2d'); const ctx = canvas.getContext('2d');
if (!ctx) return;
// Set initial canvas size // Set initial canvas size
canvas.width = window.innerWidth - 300; canvas.width = window.innerWidth - 300;
canvas.height = window.innerHeight - 100; canvas.height = window.innerHeight - 100;
// Draw history // Clear canvas first
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Draw all shapes
shapes.forEach((shape) => {
drawShape(ctx, shape);
});
// Draw all pencil strokes from history
history.forEach((action) => { history.forEach((action) => {
if (action.type === 'draw') { if (action.type === 'draw') {
drawLine(ctx, action.x1, action.y1, action.x2, action.y2, action.color, action.thickness); drawLine(ctx, action.x1, action.y1, action.x2, action.y2, action.color, action.thickness);
} }
}); });
// Draw shapes
shapes.forEach((shape) => { shapes.forEach((shape) => {
drawShape(ctx, shape); drawShape(ctx, shape);
}); });
// Draw history (for pencil drawing)
history.forEach((action) => {
if (action.type === 'draw') {
drawLine(ctx, action.x1, action.y1, action.x2, action.y2, action.color, action.thickness);
}
});
}, [history, shapes]); }, [history, shapes]);
const drawLine = (ctx, x1, y1, x2, y2, color, thickness) => {
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.strokeStyle = color;
ctx.lineWidth = thickness;
ctx.lineCap = 'round';
ctx.stroke();
};
const drawShape = (ctx, shape) => {
ctx.beginPath();
ctx.strokeStyle = shape.color;
ctx.lineWidth = shape.thickness;
ctx.lineCap = 'round';
if (shape.type === 'rectangle') {
ctx.rect(shape.x, shape.y, shape.width, shape.height);
} else if (shape.type === 'circle') {
ctx.arc(shape.x, shape.y, shape.radius, 0, Math.PI * 2);
}
ctx.stroke();
};
const handleMouseDown = (e) => { const handleMouseDown = (e) => {
setIsDrawing(true); setIsDrawing(true);
const canvas = canvasRef.current; const canvas = canvasRef.current;
@ -108,7 +130,7 @@ const DrawingCanvas = ({ color, setColor, thickness, setThickness, history, setH
ctx.stroke(); ctx.stroke();
// Update history // Update history
setHistory([...history, { setHistory(prevHistory => [...prevHistory, {
type: 'draw', type: 'draw',
x1: lastPos.x, x1: lastPos.x,
y1: lastPos.y, y1: lastPos.y,
@ -136,45 +158,56 @@ const DrawingCanvas = ({ color, setColor, thickness, setThickness, history, setH
} }
return shape; return shape;
}); });
// Add shape to history when it's created
if (updatedShapes.length > 0) {
const lastShape = updatedShapes[updatedShapes.length - 1];
setHistory(prevHistory => [...prevHistory, {
type: 'shape',
shape: lastShape
}]);
}
setShapes(updatedShapes); setShapes(updatedShapes);
} }
}; };
// Separate function to handle shape drawing
useEffect(() => {
const canvas = canvasRef.current;
const ctx = canvas.getContext('2d');
// Clear canvas and redraw all shapes
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Draw all shapes
shapes.forEach((shape) => {
drawShape(ctx, shape);
});
// Draw history (for pencil drawing)
history.forEach((action) => {
if (action.type === 'draw') {
drawLine(ctx, action.x1, action.y1, action.x2, action.y2, action.color, action.thickness);
}
});
}, [shapes, history]);
const handleMouseUp = () => { const handleMouseUp = () => {
setIsDrawing(false); setIsDrawing(false);
// Clear last position when mouse is released
setLastPosition(null); setLastPosition(null);
setUndoHistory([]);
}; };
const handleUndo = () => { const handleUndo = () => {
if (history.length > 0) { if (history.length > 0) {
setHistory(history.slice(0, -1)); // Clear the last action from history
setHistory(prevHistory => prevHistory.slice(0, -1));
// Add it to undo history
setUndoHistory(prev => [...prev, history[history.length - 1]]);
// Clear the last shape if it exists
if (shapes.length > 0) {
setShapes(prevShapes => prevShapes.slice(0, -1));
}
} }
}; };
const handleRedo = () => { const handleRedo = () => {
// Implement redo functionality if (undoHistory.length > 0) {
const lastUndo = undoHistory[undoHistory.length - 1];
// Add the action back to history
setHistory(prevHistory => [...prevHistory, lastUndo]);
// Remove it from undo history
setUndoHistory(prev => prev.slice(0, -1));
// Add the shape back if it exists
if (lastUndo.type === 'shape') {
setShapes(prevShapes => [...prevShapes, lastUndo.shape]);
}
}
}; };
return ( return (
@ -189,10 +222,10 @@ const DrawingCanvas = ({ color, setColor, thickness, setThickness, history, setH
<button onClick={() => setCurrentTool('circle')} className={`tool-button ${currentTool === 'circle' ? 'active' : ''}`}> <button onClick={() => setCurrentTool('circle')} className={`tool-button ${currentTool === 'circle' ? 'active' : ''}`}>
</button> </button>
<button onClick={handleUndo} className="tool-button"> <button onClick={handleUndo} className="tool-button" disabled={history.length === 0}>
</button> </button>
<button onClick={handleRedo} className="tool-button"> <button onClick={handleRedo} className="tool-button" disabled={undoHistory.length === 0}>
</button> </button>
<div className="color-picker"> <div className="color-picker">
@ -211,9 +244,6 @@ const DrawingCanvas = ({ color, setColor, thickness, setThickness, history, setH
onMouseDown={handleMouseDown} onMouseDown={handleMouseDown}
onMouseMove={handleMouseMove} onMouseMove={handleMouseMove}
onMouseUp={handleMouseUp} onMouseUp={handleMouseUp}
max="20"
value={thickness}
onChange={(e) => setThickness(e.target.value)}
/> />
</div> </div>
</div> </div>