Kar 2025-07-08 16:40:26 +05:30
parent a907f2781c
commit 2f32d1a166
1 changed files with 96 additions and 1 deletions

View File

@ -21,6 +21,11 @@ const drawShape = (ctx, shape) => {
ctx.stroke(); ctx.stroke();
} else if (shape.type === 'image' && shape.image) { } else if (shape.type === 'image' && shape.image) {
ctx.drawImage(shape.image, shape.x, shape.y, shape.width, shape.height); ctx.drawImage(shape.image, shape.x, shape.y, shape.width, shape.height);
} else if (shape.type === 'text' && shape.text) {
ctx.fillStyle = shape.color;
ctx.font = `${shape.thickness * 6}px sans-serif`; // Match input font size
ctx.textBaseline = 'top';
ctx.fillText(shape.text, shape.x, shape.y);
} }
}; };
@ -37,6 +42,9 @@ const DrawingCanvas = () => {
const [selectedIndex, setSelectedIndex] = useState(null); const [selectedIndex, setSelectedIndex] = useState(null);
const [offset, setOffset] = useState({ x: 0, y: 0 }); const [offset, setOffset] = useState({ x: 0, y: 0 });
const fileInputRef = useRef(null); const fileInputRef = useRef(null);
const [textInput, setTextInput] = useState('');
const [isTextInputVisible, setIsTextInputVisible] = useState(false);
const [textPosition, setTextPosition] = useState({ x: 0, y: 0 });
// Resize canvas on window resize // Resize canvas on window resize
useEffect(() => { useEffect(() => {
@ -73,12 +81,32 @@ const DrawingCanvas = () => {
ctx.save(); ctx.save();
ctx.strokeStyle = 'red'; ctx.strokeStyle = 'red';
ctx.lineWidth = 2; ctx.lineWidth = 2;
if (shape.type === 'rectangle' || shape.type === 'image') { if (shape.type === 'rectangle' || shape.type === 'image' || shape.type === 'text') {
ctx.strokeRect(shape.x, shape.y, shape.width, shape.height); ctx.strokeRect(shape.x, shape.y, shape.width, shape.height);
// Draw resize handles (corners)
const handleSize = 8;
const handles = [
[shape.x, shape.y],
[shape.x + shape.width, shape.y],
[shape.x, shape.y + shape.height],
[shape.x + shape.width, shape.y + shape.height],
];
ctx.fillStyle = 'white';
ctx.strokeStyle = 'black';
handles.forEach(([hx, hy]) => {
ctx.fillRect(hx - handleSize/2, hy - handleSize/2, handleSize, handleSize);
ctx.strokeRect(hx - handleSize/2, hy - handleSize/2, handleSize, handleSize);
});
} else if (shape.type === 'circle') { } else if (shape.type === 'circle') {
ctx.beginPath(); ctx.beginPath();
ctx.arc(shape.x, shape.y, shape.radius, 0, Math.PI * 2); ctx.arc(shape.x, shape.y, shape.radius, 0, Math.PI * 2);
ctx.stroke(); ctx.stroke();
// Draw handle at the edge (right)
const handleSize = 8;
ctx.fillStyle = 'white';
ctx.strokeStyle = 'black';
ctx.fillRect(shape.x + shape.radius - handleSize/2, shape.y - handleSize/2, handleSize, handleSize);
ctx.strokeRect(shape.x + shape.radius - handleSize/2, shape.y - handleSize/2, handleSize, handleSize);
} }
ctx.restore(); ctx.restore();
} }
@ -108,6 +136,13 @@ const DrawingCanvas = () => {
e.preventDefault(); e.preventDefault();
const { x, y } = getPos(e); const { x, y } = getPos(e);
if (currentTool === 'text') {
setTextPosition({ x, y });
setIsTextInputVisible(true);
setTextInput('');
return;
}
if (currentTool === 'select') { if (currentTool === 'select') {
// Find the topmost shape under the pointer // Find the topmost shape under the pointer
for (let i = shapes.length - 1; i >= 0; i--) { for (let i = shapes.length - 1; i >= 0; i--) {
@ -299,6 +334,20 @@ const DrawingCanvas = () => {
link.click(); link.click();
}; };
const getCursor = () => {
switch (currentTool) {
case 'pencil':
return 'crosshair';
case 'rectangle':
case 'circle':
return 'crosshair';
case 'select':
return 'move';
default:
return 'default';
}
};
return ( return (
<div className="drawing-container"> <div className="drawing-container">
<div className="toolbar"> <div className="toolbar">
@ -306,6 +355,7 @@ const DrawingCanvas = () => {
<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={() => setCurrentTool('select')} className={`tool-button ${currentTool === 'select' ? 'active' : ''}`}>🖱</button>
<button onClick={() => setCurrentTool('text')} className={`tool-button ${currentTool === 'text' ? '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>
@ -330,10 +380,55 @@ const DrawingCanvas = () => {
<canvas <canvas
ref={canvasRef} ref={canvasRef}
className="drawing-canvas" className="drawing-canvas"
style={{ cursor: getCursor() }}
onMouseDown={handlePointerDown} onMouseDown={handlePointerDown}
onMouseMove={handlePointerMove} onMouseMove={handlePointerMove}
onMouseUp={handlePointerUp} onMouseUp={handlePointerUp}
/> />
{isTextInputVisible && (
<input
type="text"
value={textInput}
autoFocus
style={{
position: 'absolute',
left: textPosition.x + (canvasRef.current?.offsetLeft || 0),
top: textPosition.y + (canvasRef.current?.offsetTop || 0),
zIndex: 10,
fontSize: `${thickness * 6}px`
}}
onChange={e => setTextInput(e.target.value)}
onBlur={() => {
if (textInput.trim() !== '') {
setShapes(prev => [
...prev,
{
type: 'text',
x: textPosition.x,
y: textPosition.y,
text: textInput,
color,
thickness,
}
]);
setHistory(prev => [...prev, deepCopyShapes([...shapes, {
type: 'text',
x: textPosition.x,
y: textPosition.y,
text: textInput,
color,
thickness,
}])]);
setUndoHistory([]);
}
setIsTextInputVisible(false);
setTextInput('');
}}
onKeyDown={e => {
if (e.key === 'Enter') e.target.blur();
}}
/>
)}
</div> </div>
</div> </div>
); );