Added basic drawing control
This commit is contained in:
parent
c12abf5706
commit
4555c9bf71
@ -34,6 +34,8 @@ function Map({
|
|||||||
const [mapTranslate, setMapTranslate] = useState({ x: 0, y: 0 });
|
const [mapTranslate, setMapTranslate] = useState({ x: 0, y: 0 });
|
||||||
const [mapScale, setMapScale] = useState(1);
|
const [mapScale, setMapScale] = useState(1);
|
||||||
|
|
||||||
|
const [selectedTool, setSelectedTool] = useState("pan");
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
interact(".map")
|
interact(".map")
|
||||||
.gesturable({
|
.gesturable({
|
||||||
@ -42,10 +44,12 @@ function Map({
|
|||||||
setMapScale((previousMapScale) =>
|
setMapScale((previousMapScale) =>
|
||||||
Math.max(Math.min(previousMapScale + event.ds, maxZoom), minZoom)
|
Math.max(Math.min(previousMapScale + event.ds, maxZoom), minZoom)
|
||||||
);
|
);
|
||||||
setMapTranslate((previousMapTranslate) => ({
|
if (selectedTool === "pan") {
|
||||||
x: previousMapTranslate.x + event.dx,
|
setMapTranslate((previousMapTranslate) => ({
|
||||||
y: previousMapTranslate.y + event.dy,
|
x: previousMapTranslate.x + event.dx,
|
||||||
}));
|
y: previousMapTranslate.y + event.dy,
|
||||||
|
}));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@ -53,10 +57,12 @@ function Map({
|
|||||||
inertia: true,
|
inertia: true,
|
||||||
listeners: {
|
listeners: {
|
||||||
move: (event) => {
|
move: (event) => {
|
||||||
// setMapTranslate((previousMapTranslate) => ({
|
if (selectedTool === "pan") {
|
||||||
// x: previousMapTranslate.x + event.dx,
|
setMapTranslate((previousMapTranslate) => ({
|
||||||
// y: previousMapTranslate.y + event.dy,
|
x: previousMapTranslate.x + event.dx,
|
||||||
// }));
|
y: previousMapTranslate.y + event.dy,
|
||||||
|
}));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -65,7 +71,7 @@ function Map({
|
|||||||
setMapTranslate({ x: 0, y: 0 });
|
setMapTranslate({ x: 0, y: 0 });
|
||||||
setMapScale(1);
|
setMapScale(1);
|
||||||
});
|
});
|
||||||
}, []);
|
}, [selectedTool]);
|
||||||
|
|
||||||
// Reset map transform when map changes
|
// Reset map transform when map changes
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -194,10 +200,15 @@ function Map({
|
|||||||
<MapDrawing
|
<MapDrawing
|
||||||
width={mapData ? mapData.width : 0}
|
width={mapData ? mapData.width : 0}
|
||||||
height={mapData ? mapData.height : 0}
|
height={mapData ? mapData.height : 0}
|
||||||
|
selectedTool={selectedTool}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
<MapControls onMapChange={onMapChange} />
|
<MapControls
|
||||||
|
onMapChange={onMapChange}
|
||||||
|
onToolChange={setSelectedTool}
|
||||||
|
selectedTool={selectedTool}
|
||||||
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
<ProxyToken
|
<ProxyToken
|
||||||
tokenClassName={mapTokenClassName}
|
tokenClassName={mapTokenClassName}
|
||||||
|
@ -9,7 +9,13 @@ import EraseToolIcon from "../icons/EraseToolIcon";
|
|||||||
import UndoIcon from "../icons/UndoIcon";
|
import UndoIcon from "../icons/UndoIcon";
|
||||||
import RedoIcon from "../icons/RedoIcon";
|
import RedoIcon from "../icons/RedoIcon";
|
||||||
|
|
||||||
function MapControls({ onMapChange }) {
|
function MapControls({
|
||||||
|
onMapChange,
|
||||||
|
onToolChange,
|
||||||
|
selectedTool,
|
||||||
|
onUndo,
|
||||||
|
onRedo,
|
||||||
|
}) {
|
||||||
const divider = (
|
const divider = (
|
||||||
<Box
|
<Box
|
||||||
my={2}
|
my={2}
|
||||||
@ -33,13 +39,28 @@ function MapControls({ onMapChange }) {
|
|||||||
</IconButton>
|
</IconButton>
|
||||||
<AddMapButton onMapChange={onMapChange} />
|
<AddMapButton onMapChange={onMapChange} />
|
||||||
{divider}
|
{divider}
|
||||||
<IconButton aria-label="Pan Tool" title="Pan Tool">
|
<IconButton
|
||||||
|
aria-label="Pan Tool"
|
||||||
|
title="Pan Tool"
|
||||||
|
onClick={() => onToolChange("pan")}
|
||||||
|
sx={{ color: selectedTool === "pan" ? "primary" : "text" }}
|
||||||
|
>
|
||||||
<PanToolIcon />
|
<PanToolIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<IconButton aria-label="Brush Tool" title="Brush Tool">
|
<IconButton
|
||||||
|
aria-label="Brush Tool"
|
||||||
|
title="Brush Tool"
|
||||||
|
onClick={() => onToolChange("brush")}
|
||||||
|
sx={{ color: selectedTool === "brush" ? "primary" : "text" }}
|
||||||
|
>
|
||||||
<BrushToolIcon />
|
<BrushToolIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<IconButton aria-label="Erase Tool" title="Erase Tool">
|
<IconButton
|
||||||
|
aria-label="Erase Tool"
|
||||||
|
title="Erase Tool"
|
||||||
|
onClick={() => onToolChange("erase")}
|
||||||
|
sx={{ color: selectedTool === "erase" ? "primary" : "text" }}
|
||||||
|
>
|
||||||
<EraseToolIcon />
|
<EraseToolIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
{divider}
|
{divider}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import React, { useRef, useEffect, useState } from "react";
|
import React, { useRef, useEffect, useState } from "react";
|
||||||
import simplify from "simplify-js";
|
import simplify from "simplify-js";
|
||||||
|
|
||||||
function MapDrawing({ width, height }) {
|
function MapDrawing({ width, height, selectedTool }) {
|
||||||
const canvasRef = useRef();
|
const canvasRef = useRef();
|
||||||
const containerRef = useRef();
|
const containerRef = useRef();
|
||||||
|
|
||||||
@ -20,13 +20,20 @@ function MapDrawing({ width, height }) {
|
|||||||
const [isMouseDown, setIsMouseDown] = useState(false);
|
const [isMouseDown, setIsMouseDown] = useState(false);
|
||||||
function handleMouseDown(event) {
|
function handleMouseDown(event) {
|
||||||
setIsMouseDown(true);
|
setIsMouseDown(true);
|
||||||
const position = getMousePosition(event);
|
if (selectedTool === "brush") {
|
||||||
setShapes((prevShapes) => [...prevShapes, { points: [position] }]);
|
const position = getMousePosition(event);
|
||||||
|
setShapes((prevShapes) => [...prevShapes, { points: [position] }]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const [mousePosition, setMousePosition] = useState({ x: 0, y: 0 });
|
||||||
function handleMouseMove(event) {
|
function handleMouseMove(event) {
|
||||||
if (isMouseDown) {
|
const position = getMousePosition(event);
|
||||||
const position = getMousePosition(event);
|
if (selectedTool === "erase") {
|
||||||
|
setMousePosition(position);
|
||||||
|
}
|
||||||
|
if (isMouseDown && selectedTool === "brush") {
|
||||||
|
setMousePosition(position);
|
||||||
setShapes((prevShapes) => {
|
setShapes((prevShapes) => {
|
||||||
const currentShape = prevShapes.slice(-1)[0];
|
const currentShape = prevShapes.slice(-1)[0];
|
||||||
const otherShapes = prevShapes.slice(0, -1);
|
const otherShapes = prevShapes.slice(0, -1);
|
||||||
@ -37,12 +44,14 @@ function MapDrawing({ width, height }) {
|
|||||||
|
|
||||||
function handleMouseUp(event) {
|
function handleMouseUp(event) {
|
||||||
setIsMouseDown(false);
|
setIsMouseDown(false);
|
||||||
setShapes((prevShapes) => {
|
if (selectedTool === "brush") {
|
||||||
const currentShape = prevShapes.slice(-1)[0];
|
setShapes((prevShapes) => {
|
||||||
const otherShapes = prevShapes.slice(0, -1);
|
const currentShape = prevShapes.slice(-1)[0];
|
||||||
const simplified = simplify(currentShape.points, 0.001);
|
const otherShapes = prevShapes.slice(0, -1);
|
||||||
return [...otherShapes, { points: simplified }];
|
const simplified = simplify(currentShape.points, 0.001);
|
||||||
});
|
return [...otherShapes, { points: simplified }];
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -51,18 +60,43 @@ function MapDrawing({ width, height }) {
|
|||||||
const context = canvas.getContext("2d");
|
const context = canvas.getContext("2d");
|
||||||
|
|
||||||
context.clearRect(0, 0, width, height);
|
context.clearRect(0, 0, width, height);
|
||||||
for (let shape of shapes) {
|
let erasedShapes = [];
|
||||||
context.beginPath();
|
for (let [index, shape] of shapes.entries()) {
|
||||||
context.moveTo(shape.points[0].x * width, shape.points[0].y * height);
|
const path = new Path2D();
|
||||||
|
path.moveTo(shape.points[0].x * width, shape.points[0].y * height);
|
||||||
for (let point of shape.points.slice(1)) {
|
for (let point of shape.points.slice(1)) {
|
||||||
context.lineTo(point.x * width, point.y * height);
|
path.lineTo(point.x * width, point.y * height);
|
||||||
}
|
}
|
||||||
context.closePath();
|
path.closePath();
|
||||||
context.stroke();
|
let color = "#000000";
|
||||||
context.fill();
|
if (selectedTool === "erase") {
|
||||||
|
if (
|
||||||
|
context.isPointInPath(
|
||||||
|
path,
|
||||||
|
mousePosition.x * width,
|
||||||
|
mousePosition.y * height
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
color = "#BB99FF";
|
||||||
|
if (isMouseDown) {
|
||||||
|
erasedShapes.push(index);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
context.fillStyle = color;
|
||||||
|
context.strokeStyle = color;
|
||||||
|
context.stroke(path);
|
||||||
|
context.fill(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (erasedShapes.length > 0) {
|
||||||
|
setShapes((prevShapes) =>
|
||||||
|
prevShapes.filter((_, i) => !erasedShapes.includes(i))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [shapes, width, height]);
|
}, [shapes, width, height, mousePosition, isMouseDown, selectedTool]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
Loading…
Reference in New Issue
Block a user