main
parent
274974db10
commit
520099b31d
|
@ -34,6 +34,8 @@ const DrawingCanvas = () => {
|
||||||
const [currentTool, setCurrentTool] = useState('pencil');
|
const [currentTool, setCurrentTool] = useState('pencil');
|
||||||
const [color, setColor] = useState('#000000');
|
const [color, setColor] = useState('#000000');
|
||||||
const [thickness, setThickness] = useState(2);
|
const [thickness, setThickness] = useState(2);
|
||||||
|
const [selectedIndex, setSelectedIndex] = useState(null);
|
||||||
|
const [offset, setOffset] = useState({ x: 0, y: 0 });
|
||||||
const fileInputRef = useRef(null);
|
const fileInputRef = useRef(null);
|
||||||
|
|
||||||
// Resize canvas on window resize
|
// Resize canvas on window resize
|
||||||
|
@ -63,7 +65,24 @@ const DrawingCanvas = () => {
|
||||||
ctx.putImageData(action.imageData, 0, 0);
|
ctx.putImageData(action.imageData, 0, 0);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, [shapes, history]);
|
|
||||||
|
// After drawing all shapes
|
||||||
|
if (selectedIndex !== null && shapes[selectedIndex]) {
|
||||||
|
const ctx = canvasRef.current.getContext('2d');
|
||||||
|
const shape = shapes[selectedIndex];
|
||||||
|
ctx.save();
|
||||||
|
ctx.strokeStyle = 'red';
|
||||||
|
ctx.lineWidth = 2;
|
||||||
|
if (shape.type === 'rectangle' || shape.type === 'image') {
|
||||||
|
ctx.strokeRect(shape.x, shape.y, shape.width, shape.height);
|
||||||
|
} else if (shape.type === 'circle') {
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(shape.x, shape.y, shape.radius, 0, Math.PI * 2);
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
ctx.restore();
|
||||||
|
}
|
||||||
|
}, [shapes, history, selectedIndex]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
redraw();
|
redraw();
|
||||||
|
@ -88,6 +107,32 @@ const DrawingCanvas = () => {
|
||||||
const handlePointerDown = (e) => {
|
const handlePointerDown = (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const { x, y } = getPos(e);
|
const { x, y } = getPos(e);
|
||||||
|
|
||||||
|
if (currentTool === 'select') {
|
||||||
|
// Find the topmost shape under the pointer
|
||||||
|
for (let i = shapes.length - 1; i >= 0; i--) {
|
||||||
|
const shape = shapes[i];
|
||||||
|
if (
|
||||||
|
(shape.type === 'rectangle' &&
|
||||||
|
x >= shape.x && x <= shape.x + shape.width &&
|
||||||
|
y >= shape.y && y <= shape.y + shape.height) ||
|
||||||
|
(shape.type === 'circle' &&
|
||||||
|
Math.sqrt((x - shape.x) ** 2 + (y - shape.y) ** 2) <= shape.radius) ||
|
||||||
|
(shape.type === 'image' &&
|
||||||
|
x >= shape.x && x <= shape.x + shape.width &&
|
||||||
|
y >= shape.y && y <= shape.y + shape.height)
|
||||||
|
) {
|
||||||
|
setSelectedIndex(i);
|
||||||
|
setOffset({ x: x - shape.x, y: y - shape.y });
|
||||||
|
setIsDrawing(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setSelectedIndex(null);
|
||||||
|
setIsDrawing(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
setIsDrawing(true);
|
setIsDrawing(true);
|
||||||
|
|
||||||
if (currentTool === 'pencil') {
|
if (currentTool === 'pencil') {
|
||||||
|
@ -120,6 +165,19 @@ const DrawingCanvas = () => {
|
||||||
if (!isDrawing) return;
|
if (!isDrawing) return;
|
||||||
const { x, y } = getPos(e);
|
const { x, y } = getPos(e);
|
||||||
|
|
||||||
|
if (currentTool === 'select' && selectedIndex !== null) {
|
||||||
|
setShapes(prev => {
|
||||||
|
const updated = [...prev];
|
||||||
|
const shape = { ...updated[selectedIndex] };
|
||||||
|
// Move shape based on offset
|
||||||
|
shape.x = x - offset.x;
|
||||||
|
shape.y = y - offset.y;
|
||||||
|
updated[selectedIndex] = shape;
|
||||||
|
return updated;
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (currentTool === 'pencil') {
|
if (currentTool === 'pencil') {
|
||||||
setShapes(prev => {
|
setShapes(prev => {
|
||||||
if (prev.length === 0) return prev;
|
if (prev.length === 0) return prev;
|
||||||
|
@ -151,6 +209,7 @@ const DrawingCanvas = () => {
|
||||||
const handlePointerUp = () => {
|
const handlePointerUp = () => {
|
||||||
setIsDrawing(false);
|
setIsDrawing(false);
|
||||||
setLastPosition(null);
|
setLastPosition(null);
|
||||||
|
setSelectedIndex(null);
|
||||||
// Save a deep copy of shapes for undo/redo
|
// Save a deep copy of shapes for undo/redo
|
||||||
setHistory(prev => [...prev, deepCopyShapes(shapes)]);
|
setHistory(prev => [...prev, deepCopyShapes(shapes)]);
|
||||||
setUndoHistory([]);
|
setUndoHistory([]);
|
||||||
|
@ -232,6 +291,7 @@ const DrawingCanvas = () => {
|
||||||
<button onClick={() => setCurrentTool('pencil')} className={`tool-button ${currentTool === 'pencil' ? 'active' : ''}`}>✏️</button>
|
<button onClick={() => setCurrentTool('pencil')} className={`tool-button ${currentTool === 'pencil' ? 'active' : ''}`}>✏️</button>
|
||||||
<button onClick={() => setCurrentTool('rectangle')} className={`tool-button ${currentTool === 'rectangle' ? 'active' : ''}`}>🟨</button>
|
<button onClick={() => setCurrentTool('rectangle')} className={`tool-button ${currentTool === 'rectangle' ? 'active' : ''}`}>🟨</button>
|
||||||
<button onClick={() => setCurrentTool('circle')} className={`tool-button ${currentTool === 'circle' ? 'active' : ''}`}>⭕</button>
|
<button onClick={() => setCurrentTool('circle')} className={`tool-button ${currentTool === 'circle' ? 'active' : ''}`}>⭕</button>
|
||||||
|
<button onClick={() => setCurrentTool('select')} className={`tool-button ${currentTool === 'select' ? 'active' : ''}`}>🖱️</button>
|
||||||
<button onClick={handleUndo} className="tool-button" disabled={history.length === 0}>↺</button>
|
<button onClick={handleUndo} className="tool-button" disabled={history.length === 0}>↺</button>
|
||||||
<button onClick={handleRedo} className="tool-button" disabled={undoHistory.length === 0}>↻</button>
|
<button onClick={handleRedo} className="tool-button" disabled={undoHistory.length === 0}>↻</button>
|
||||||
<button onClick={() => fileInputRef.current.click()} className="tool-button">🖼️ Insert Image</button>
|
<button onClick={() => fileInputRef.current.click()} className="tool-button">🖼️ Insert Image</button>
|
||||||
|
|
Loading…
Reference in New Issue