Added undo and redo and map control validation
This commit is contained in:
@@ -1,12 +1,18 @@
|
||||
import React, { useRef, useEffect, useState } from "react";
|
||||
import simplify from "simplify-js";
|
||||
import shortid from "shortid";
|
||||
|
||||
function MapDrawing({ width, height, selectedTool }) {
|
||||
function MapDrawing({
|
||||
width,
|
||||
height,
|
||||
selectedTool,
|
||||
shapes,
|
||||
onShapeAdd,
|
||||
onShapeRemove,
|
||||
}) {
|
||||
const canvasRef = useRef();
|
||||
const containerRef = useRef();
|
||||
|
||||
const [shapes, setShapes] = useState([]);
|
||||
|
||||
function getMousePosition(event) {
|
||||
const container = containerRef.current;
|
||||
if (container) {
|
||||
@@ -17,12 +23,13 @@ function MapDrawing({ width, height, selectedTool }) {
|
||||
}
|
||||
}
|
||||
|
||||
const [brushPoints, setBrushPoints] = useState([]);
|
||||
const [isMouseDown, setIsMouseDown] = useState(false);
|
||||
function handleMouseDown(event) {
|
||||
setIsMouseDown(true);
|
||||
if (selectedTool === "brush") {
|
||||
const position = getMousePosition(event);
|
||||
setShapes((prevShapes) => [...prevShapes, { points: [position] }]);
|
||||
setBrushPoints([position]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,41 +41,50 @@ function MapDrawing({ width, height, selectedTool }) {
|
||||
}
|
||||
if (isMouseDown && selectedTool === "brush") {
|
||||
setMousePosition(position);
|
||||
setShapes((prevShapes) => {
|
||||
const currentShape = prevShapes.slice(-1)[0];
|
||||
const otherShapes = prevShapes.slice(0, -1);
|
||||
return [...otherShapes, { points: [...currentShape.points, position] }];
|
||||
});
|
||||
setBrushPoints((prevPoints) => [...prevPoints, position]);
|
||||
}
|
||||
}
|
||||
|
||||
function handleMouseUp(event) {
|
||||
setIsMouseDown(false);
|
||||
if (selectedTool === "brush") {
|
||||
setShapes((prevShapes) => {
|
||||
const currentShape = prevShapes.slice(-1)[0];
|
||||
const otherShapes = prevShapes.slice(0, -1);
|
||||
const simplified = simplify(currentShape.points, 0.001);
|
||||
return [...otherShapes, { points: simplified }];
|
||||
});
|
||||
const simplifiedPoints = simplify(brushPoints, 0.001);
|
||||
onShapeAdd({ id: shortid.generate(), points: simplifiedPoints });
|
||||
setBrushPoints([]);
|
||||
}
|
||||
if (selectedTool === "erase" && hoveredShapeRef.current) {
|
||||
onShapeRemove(hoveredShapeRef.current.id);
|
||||
}
|
||||
}
|
||||
|
||||
const hoveredShapeRef = useRef(null);
|
||||
useEffect(() => {
|
||||
function pointsToPath(points) {
|
||||
const path = new Path2D();
|
||||
path.moveTo(points[0].x * width, points[0].y * height);
|
||||
for (let point of points.slice(1)) {
|
||||
path.lineTo(point.x * width, point.y * height);
|
||||
}
|
||||
path.closePath();
|
||||
return path;
|
||||
}
|
||||
|
||||
function drawPath(path, color, context) {
|
||||
context.fillStyle = color;
|
||||
context.strokeStyle = color;
|
||||
context.stroke(path);
|
||||
context.fill(path);
|
||||
}
|
||||
|
||||
const canvas = canvasRef.current;
|
||||
if (canvas) {
|
||||
const context = canvas.getContext("2d");
|
||||
|
||||
context.clearRect(0, 0, width, height);
|
||||
let erasedShapes = [];
|
||||
for (let [index, shape] of shapes.entries()) {
|
||||
const path = new Path2D();
|
||||
path.moveTo(shape.points[0].x * width, shape.points[0].y * height);
|
||||
for (let point of shape.points.slice(1)) {
|
||||
path.lineTo(point.x * width, point.y * height);
|
||||
}
|
||||
path.closePath();
|
||||
let color = "#000000";
|
||||
let hoveredShape = null;
|
||||
for (let shape of shapes) {
|
||||
const path = pointsToPath(shape.points);
|
||||
// Detect hover
|
||||
if (selectedTool === "erase") {
|
||||
if (
|
||||
context.isPointInPath(
|
||||
@@ -77,26 +93,30 @@ function MapDrawing({ width, height, selectedTool }) {
|
||||
mousePosition.y * height
|
||||
)
|
||||
) {
|
||||
color = "#BB99FF";
|
||||
if (isMouseDown) {
|
||||
erasedShapes.push(index);
|
||||
continue;
|
||||
}
|
||||
hoveredShape = shape;
|
||||
}
|
||||
}
|
||||
context.fillStyle = color;
|
||||
context.strokeStyle = color;
|
||||
context.stroke(path);
|
||||
context.fill(path);
|
||||
drawPath(path, "#000000", context);
|
||||
}
|
||||
|
||||
if (erasedShapes.length > 0) {
|
||||
setShapes((prevShapes) =>
|
||||
prevShapes.filter((_, i) => !erasedShapes.includes(i))
|
||||
);
|
||||
if (selectedTool === "brush" && brushPoints.length > 0) {
|
||||
const path = pointsToPath(brushPoints);
|
||||
drawPath(path, "#000000", context);
|
||||
}
|
||||
if (hoveredShape) {
|
||||
const path = pointsToPath(hoveredShape.points);
|
||||
drawPath(path, "#BB99FF", context);
|
||||
}
|
||||
hoveredShapeRef.current = hoveredShape;
|
||||
}
|
||||
}, [shapes, width, height, mousePosition, isMouseDown, selectedTool]);
|
||||
}, [
|
||||
shapes,
|
||||
width,
|
||||
height,
|
||||
mousePosition,
|
||||
isMouseDown,
|
||||
selectedTool,
|
||||
brushPoints,
|
||||
]);
|
||||
|
||||
return (
|
||||
<div
|
||||
|
||||
Reference in New Issue
Block a user