feat: lasso tool

This commit is contained in:
trafficlunar 2025-01-18 22:36:03 +00:00
parent 4ca631d4d2
commit e0d25bb222
3 changed files with 41 additions and 18 deletions

View file

@ -90,7 +90,8 @@ function Canvas() {
}, [dragging, holdingAlt, tool, setCssCursor]); }, [dragging, holdingAlt, tool, setCssCursor]);
const onToolUse = useCallback(() => { const onToolUse = useCallback(() => {
// Calculate the top-left position of the radius // If number is odd, cursor is in the center
// if number is even, cursor is in the top-left corner
const getRadiusPosition = (): Position => { const getRadiusPosition = (): Position => {
const halfSize = Math.floor(radius / 2); const halfSize = Math.floor(radius / 2);
const x = mouseCoords.x - (radius % 2 === 0 ? 0 : halfSize); const x = mouseCoords.x - (radius % 2 === 0 ? 0 : halfSize);
@ -144,6 +145,13 @@ function Canvas() {
); );
break; break;
} }
case "lasso": {
setSelectionCoords((prev) => {
const exists = prev.some(([x2, y2]) => x2 === mouseCoords.x && y2 === mouseCoords.y);
return exists ? prev : [...prev, [mouseCoords.x, mouseCoords.y]];
});
break;
}
case "pencil": { case "pencil": {
if (selectedBlock == "air") { if (selectedBlock == "air") {
eraseTool(); eraseTool();
@ -296,6 +304,14 @@ function Canvas() {
setTool("hand"); setTool("hand");
setCssCursor("grabbing"); setCssCursor("grabbing");
break; break;
case "Alt":
setHoldingAlt(true);
setCssCursor("zoom-out");
break;
case "Delete": {
setBlocks((prev) => prev.filter((b) => !selectionCoordsRef.current.some(([x2, y2]) => x2 === b.x && y2 === b.y)));
break;
}
case "1": case "1":
setTool("hand"); setTool("hand");
break; break;
@ -306,25 +322,20 @@ function Canvas() {
setTool("rectangle-select"); setTool("rectangle-select");
break; break;
case "4": case "4":
setTool("pencil"); setTool("lasso");
break; break;
case "5": case "5":
setTool("eraser"); setTool("pencil");
break; break;
case "6": case "6":
setTool("eyedropper"); setTool("eraser");
break; break;
case "7": case "7":
setTool("eyedropper");
break;
case "8":
setTool("zoom"); setTool("zoom");
break; break;
case "Alt":
setHoldingAlt(true);
setCssCursor("zoom-out");
break;
case "Delete": {
setBlocks((prev) => prev.filter((b) => !selectionCoordsRef.current.some(([x2, y2]) => x2 === b.x && y2 === b.y)));
break;
}
} }
}; };

View file

@ -1,5 +1,5 @@
import { useContext } from "react"; import { useContext } from "react";
import { EraserIcon, HandIcon, MousePointer2Icon, PencilIcon, PipetteIcon, SquareDashedIcon, ZoomInIcon } from "lucide-react"; import { EraserIcon, HandIcon, LassoIcon, MousePointer2Icon, PencilIcon, PipetteIcon, SquareDashedIcon, ZoomInIcon } from "lucide-react";
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group"; import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group";
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip"; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";
@ -57,6 +57,18 @@ function Toolbar() {
</TooltipContent> </TooltipContent>
</Tooltip> </Tooltip>
{/* Lasso */}
<Tooltip delayDuration={0}>
<TooltipTrigger>
<ToggleGroupItem value="lasso" className="!p-0 !h-8 !min-w-8">
<LassoIcon />
</ToggleGroupItem>
</TooltipTrigger>
<TooltipContent side="right" sideOffset={10}>
<p>Lasso (4)</p>
</TooltipContent>
</Tooltip>
{/* Pencil */} {/* Pencil */}
<Tooltip delayDuration={0}> <Tooltip delayDuration={0}>
<TooltipTrigger> <TooltipTrigger>
@ -65,7 +77,7 @@ function Toolbar() {
</ToggleGroupItem> </ToggleGroupItem>
</TooltipTrigger> </TooltipTrigger>
<TooltipContent side="right" sideOffset={10}> <TooltipContent side="right" sideOffset={10}>
<p>Pencil (4)</p> <p>Pencil (5)</p>
</TooltipContent> </TooltipContent>
</Tooltip> </Tooltip>
@ -77,7 +89,7 @@ function Toolbar() {
</ToggleGroupItem> </ToggleGroupItem>
</TooltipTrigger> </TooltipTrigger>
<TooltipContent side="right" sideOffset={10}> <TooltipContent side="right" sideOffset={10}>
<p>Eraser (5)</p> <p>Eraser (6)</p>
</TooltipContent> </TooltipContent>
</Tooltip> </Tooltip>
@ -89,7 +101,7 @@ function Toolbar() {
</ToggleGroupItem> </ToggleGroupItem>
</TooltipTrigger> </TooltipTrigger>
<TooltipContent side="right" sideOffset={10}> <TooltipContent side="right" sideOffset={10}>
<p>Eyedropper (6)</p> <p>Eyedropper (7)</p>
</TooltipContent> </TooltipContent>
</Tooltip> </Tooltip>
@ -101,7 +113,7 @@ function Toolbar() {
</ToggleGroupItem> </ToggleGroupItem>
</TooltipTrigger> </TooltipTrigger>
<TooltipContent side="right" sideOffset={10}> <TooltipContent side="right" sideOffset={10}>
<p>Zoom (7)</p> <p>Zoom (8)</p>
</TooltipContent> </TooltipContent>
</Tooltip> </Tooltip>

2
src/types.d.ts vendored
View file

@ -23,7 +23,7 @@ interface Block extends Position {
type CoordinateArray = [number, number][]; type CoordinateArray = [number, number][];
type Tool = "hand" | "move" | "rectangle-select" | "pencil" | "eraser" | "eyedropper" | "zoom"; type Tool = "hand" | "move" | "rectangle-select" | "lasso" | "pencil" | "eraser" | "eyedropper" | "zoom";
interface Settings { interface Settings {
grid: boolean; grid: boolean;