fix: holes in eraser tool

This commit is contained in:
trafficlunar 2025-02-16 20:06:32 +00:00
parent 620f15aaed
commit 776a36c11d
2 changed files with 38 additions and 11 deletions

View file

@ -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) => {

View file

@ -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<Position | null>(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 };
}