From e0d25bb222aecb01f9c996d4f8ef7b30a03dcde8 Mon Sep 17 00:00:00 2001 From: trafficlunar Date: Sat, 18 Jan 2025 22:36:03 +0000 Subject: [PATCH] feat: lasso tool --- src/components/canvas/Canvas.tsx | 35 +++++++++++++++++++++----------- src/components/toolbar/index.tsx | 22 +++++++++++++++----- src/types.d.ts | 2 +- 3 files changed, 41 insertions(+), 18 deletions(-) diff --git a/src/components/canvas/Canvas.tsx b/src/components/canvas/Canvas.tsx index c19a254..79c4c16 100644 --- a/src/components/canvas/Canvas.tsx +++ b/src/components/canvas/Canvas.tsx @@ -90,7 +90,8 @@ function Canvas() { }, [dragging, holdingAlt, tool, setCssCursor]); 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 halfSize = Math.floor(radius / 2); const x = mouseCoords.x - (radius % 2 === 0 ? 0 : halfSize); @@ -144,6 +145,13 @@ function Canvas() { ); 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": { if (selectedBlock == "air") { eraseTool(); @@ -296,6 +304,14 @@ function Canvas() { setTool("hand"); setCssCursor("grabbing"); 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": setTool("hand"); break; @@ -306,25 +322,20 @@ function Canvas() { setTool("rectangle-select"); break; case "4": - setTool("pencil"); + setTool("lasso"); break; case "5": - setTool("eraser"); + setTool("pencil"); break; case "6": - setTool("eyedropper"); + setTool("eraser"); break; case "7": + setTool("eyedropper"); + break; + case "8": setTool("zoom"); 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; - } } }; diff --git a/src/components/toolbar/index.tsx b/src/components/toolbar/index.tsx index bcf5fc9..3342d5f 100644 --- a/src/components/toolbar/index.tsx +++ b/src/components/toolbar/index.tsx @@ -1,5 +1,5 @@ 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 { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip"; @@ -57,6 +57,18 @@ function Toolbar() { + {/* Lasso */} + + + + + + + +

Lasso (4)

+
+
+ {/* Pencil */} @@ -65,7 +77,7 @@ function Toolbar() { -

Pencil (4)

+

Pencil (5)

@@ -77,7 +89,7 @@ function Toolbar() { -

Eraser (5)

+

Eraser (6)

@@ -89,7 +101,7 @@ function Toolbar() { -

Eyedropper (6)

+

Eyedropper (7)

@@ -101,7 +113,7 @@ function Toolbar() { -

Zoom (7)

+

Zoom (8)

diff --git a/src/types.d.ts b/src/types.d.ts index fce134d..373e790 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -23,7 +23,7 @@ interface Block extends Position { 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 { grid: boolean;