feat: add pencil tool
This commit is contained in:
parent
f50f109d27
commit
6f5fdfb799
2 changed files with 57 additions and 9 deletions
64
src/App.tsx
64
src/App.tsx
|
|
@ -1,6 +1,6 @@
|
||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import { Layer, Stage } from "react-konva";
|
import { Layer, Stage } from "react-konva";
|
||||||
import { Hand } from "lucide-react";
|
import { Hand, Pencil } from "lucide-react";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Menubar,
|
Menubar,
|
||||||
|
|
@ -34,9 +34,25 @@ function App() {
|
||||||
const [mousePosition, setMousePosition] = useState<Position>({ x: 0, y: 0 });
|
const [mousePosition, setMousePosition] = useState<Position>({ x: 0, y: 0 });
|
||||||
|
|
||||||
const [tool, setTool] = useState<Tool>("hand");
|
const [tool, setTool] = useState<Tool>("hand");
|
||||||
|
const [selectedBlock, setSelectedBlock] = useState("stone");
|
||||||
const [blocks, setBlocks] = useState<Block[]>([]);
|
const [blocks, setBlocks] = useState<Block[]>([]);
|
||||||
|
|
||||||
const [cssCursor, setCssCursor] = useState("grab");
|
const [cssCursor, setCssCursor] = useState("grab");
|
||||||
|
const [mouseDown, setMouseDown] = useState(false);
|
||||||
|
|
||||||
|
const onToolChange = (value) => {
|
||||||
|
setTool(value);
|
||||||
|
|
||||||
|
switch (value) {
|
||||||
|
case "hand":
|
||||||
|
setCssCursor("grab");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
setCssCursor("auto");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const onMouseMove = (e) => {
|
const onMouseMove = (e) => {
|
||||||
const stage = e.target.getStage();
|
const stage = e.target.getStage();
|
||||||
|
|
@ -47,15 +63,15 @@ function App() {
|
||||||
x: (pointer.x - stage.x()) / oldScale,
|
x: (pointer.x - stage.x()) / oldScale,
|
||||||
y: (pointer.y - stage.y()) / oldScale,
|
y: (pointer.y - stage.y()) / oldScale,
|
||||||
});
|
});
|
||||||
};
|
|
||||||
|
|
||||||
const onMouseDown = (e) => {
|
if (mouseDown) {
|
||||||
if (tool == "hand") {
|
onClick(e);
|
||||||
setCssCursor("grabbing");
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const onMouseUp = (e) => {
|
const onMouseUp = (e) => {
|
||||||
|
setMouseDown(false);
|
||||||
|
|
||||||
if (tool == "hand") {
|
if (tool == "hand") {
|
||||||
setCssCursor("grab");
|
setCssCursor("grab");
|
||||||
}
|
}
|
||||||
|
|
@ -75,6 +91,28 @@ function App() {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const onClick = (e) => {
|
||||||
|
switch (tool) {
|
||||||
|
case "hand":
|
||||||
|
setCssCursor("grabbing");
|
||||||
|
break;
|
||||||
|
case "pencil": {
|
||||||
|
const blockX = Math.floor(mousePosition.x / 16);
|
||||||
|
const blockY = Math.floor(mousePosition.y / 16);
|
||||||
|
const updatedBlocks = blocks.filter((b) => !(b.x === blockX && b.y === blockY));
|
||||||
|
|
||||||
|
setBlocks([
|
||||||
|
...updatedBlocks,
|
||||||
|
{
|
||||||
|
name: selectedBlock,
|
||||||
|
x: blockX,
|
||||||
|
y: blockY,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (stageContainerRef.current && stageRef.current) {
|
if (stageContainerRef.current && stageRef.current) {
|
||||||
setStageSize({
|
setStageSize({
|
||||||
|
|
@ -118,26 +156,36 @@ function App() {
|
||||||
</MenubarMenu>
|
</MenubarMenu>
|
||||||
</Menubar>
|
</Menubar>
|
||||||
|
|
||||||
<ToggleGroup type="single" size={"sm"} value={tool} className="flex flex-col justify-start py-0.5 border-r border-zinc-200 dark:border-zinc-800 bg-white dark:bg-zinc-950">
|
<ToggleGroup
|
||||||
|
type="single"
|
||||||
|
size={"sm"}
|
||||||
|
value={tool}
|
||||||
|
onValueChange={onToolChange}
|
||||||
|
className="flex flex-col gap-0.5 justify-start py-0.5 border-r border-zinc-200 dark:border-zinc-800 bg-white dark:bg-zinc-950"
|
||||||
|
>
|
||||||
<ToggleGroupItem value="hand">
|
<ToggleGroupItem value="hand">
|
||||||
<Hand />
|
<Hand />
|
||||||
</ToggleGroupItem>
|
</ToggleGroupItem>
|
||||||
|
<ToggleGroupItem value="pencil">
|
||||||
|
<Pencil />
|
||||||
|
</ToggleGroupItem>
|
||||||
</ToggleGroup>
|
</ToggleGroup>
|
||||||
|
|
||||||
<div ref={stageContainerRef} className="relative w-full h-full">
|
<div ref={stageContainerRef} className="relative w-full h-full">
|
||||||
<Stage
|
<Stage
|
||||||
width={stageSize.width}
|
width={stageSize.width}
|
||||||
height={stageSize.height}
|
height={stageSize.height}
|
||||||
draggable
|
draggable={tool == "hand"}
|
||||||
ref={stageRef}
|
ref={stageRef}
|
||||||
x={stageCoords.x}
|
x={stageCoords.x}
|
||||||
y={stageCoords.y}
|
y={stageCoords.y}
|
||||||
scaleX={stageScale}
|
scaleX={stageScale}
|
||||||
scaleY={stageScale}
|
scaleY={stageScale}
|
||||||
onMouseMove={onMouseMove}
|
onMouseMove={onMouseMove}
|
||||||
onMouseDown={onMouseDown}
|
onMouseDown={() => setMouseDown(true)}
|
||||||
onMouseUp={onMouseUp}
|
onMouseUp={onMouseUp}
|
||||||
onWheel={onWheel}
|
onWheel={onWheel}
|
||||||
|
onClick={onClick}
|
||||||
style={{ cursor: cssCursor }}
|
style={{ cursor: cssCursor }}
|
||||||
>
|
>
|
||||||
<Layer imageSmoothingEnabled={false}>
|
<Layer imageSmoothingEnabled={false}>
|
||||||
|
|
|
||||||
2
src/types.d.ts
vendored
2
src/types.d.ts
vendored
|
|
@ -7,4 +7,4 @@ interface Block extends Position {
|
||||||
name: string;
|
name: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
type Tool = "hand";
|
type Tool = "hand" | "pencil";
|
||||||
Loading…
Reference in a new issue