diff --git a/src/components/canvas/Canvas.tsx b/src/components/canvas/Canvas.tsx index 9c02425..0b4ba15 100644 --- a/src/components/canvas/Canvas.tsx +++ b/src/components/canvas/Canvas.tsx @@ -189,6 +189,7 @@ function Canvas() { updateCssCursor(); pencilTool.stop(); + eraserTool.stop(); // History entries for pencil and eraser if (tool === "pencil" || tool === "eraser") { @@ -212,7 +213,7 @@ function Canvas() { () => setSelectionCoords([...prevSelection]) ); } - }, [updateCssCursor, pencilTool, blocks, tool, addHistory, setBlocks, selectionCoords, setSelectionCoords]); + }, [updateCssCursor, pencilTool, eraserTool, blocks, tool, addHistory, setBlocks, selectionCoords, setSelectionCoords]); const onWheel = useCallback( (e: React.WheelEvent) => { diff --git a/src/hooks/tools/eraser.ts b/src/hooks/tools/eraser.ts index dcc9320..625487e 100644 --- a/src/hooks/tools/eraser.ts +++ b/src/hooks/tools/eraser.ts @@ -1,10 +1,11 @@ -import { useContext } from "react"; +import { useContext, useRef } from "react"; import { CanvasContext } from "@/context/Canvas"; import { SelectionContext } from "@/context/Selection"; import { ToolContext } from "@/context/Tool"; import { useRadiusPosition } from "../useRadiusPosition"; +import { interpolate } from "@/utils/interpolate"; export function useEraserTool(mouseCoords: Position) { const { blocks, setBlocks } = useContext(CanvasContext); @@ -12,16 +13,41 @@ export function useEraserTool(mouseCoords: Position) { const { radius } = useContext(ToolContext); const radiusPosition = useRadiusPosition(mouseCoords); + const lastPosition = useRef(null); - const use = () => { - const updated = blocks.filter((block) => { - const withinRadius = - block.x >= radiusPosition.x && block.x < radiusPosition.x + radius && block.y >= radiusPosition.y && block.y < radiusPosition.y + radius; - return !withinRadius || !isInSelection(block.x, block.y); - }); - - setBlocks(updated); + const stop = () => { + lastPosition.current = null; }; - return { use }; + const use = () => { + const positions: Position[] = []; + + const eraseBlock = (x: number, y: number) => { + if (isInSelection(x, y)) { + positions.push({ x, y }); + } + }; + + // Interpolate to ensure continuous erasing + if (lastPosition.current) { + const interpolatedPositions = interpolate(radius, lastPosition.current, radiusPosition); + if (!interpolatedPositions) return; + + interpolatedPositions.forEach(({ x, y }) => eraseBlock(x, y)); + } else { + for (let x = 0; x < radius; x++) { + for (let y = 0; y < radius; y++) { + eraseBlock(radiusPosition.x + x, radiusPosition.y + y); + } + } + } + + // Filter out erased blocks + const updatedBlocks = blocks.filter((block) => !positions.some((b) => block.x === b.x && block.y === b.y)); + + setBlocks(updatedBlocks); + lastPosition.current = radiusPosition; + }; + + return { stop, use }; }