2020-04-18 18:54:13 +10:00
|
|
|
import React, { useRef, useEffect, useState } from "react";
|
2020-04-18 19:09:48 +10:00
|
|
|
import simplify from "simplify-js";
|
2020-04-19 13:33:31 +10:00
|
|
|
import shortid from "shortid";
|
2020-04-18 18:11:21 +10:00
|
|
|
|
2020-04-19 13:33:31 +10:00
|
|
|
function MapDrawing({
|
|
|
|
|
width,
|
|
|
|
|
height,
|
|
|
|
|
selectedTool,
|
|
|
|
|
shapes,
|
|
|
|
|
onShapeAdd,
|
|
|
|
|
onShapeRemove,
|
|
|
|
|
}) {
|
2020-04-18 18:54:13 +10:00
|
|
|
const canvasRef = useRef();
|
2020-04-18 18:11:21 +10:00
|
|
|
const containerRef = useRef();
|
|
|
|
|
|
|
|
|
|
function getMousePosition(event) {
|
|
|
|
|
const container = containerRef.current;
|
|
|
|
|
if (container) {
|
|
|
|
|
const containerRect = container.getBoundingClientRect();
|
|
|
|
|
const x = (event.clientX - containerRect.x) / containerRect.width;
|
|
|
|
|
const y = (event.clientY - containerRect.y) / containerRect.height;
|
2020-04-18 19:09:48 +10:00
|
|
|
return { x, y };
|
2020-04-18 18:11:21 +10:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-19 13:33:31 +10:00
|
|
|
const [brushPoints, setBrushPoints] = useState([]);
|
2020-04-18 18:54:13 +10:00
|
|
|
const [isMouseDown, setIsMouseDown] = useState(false);
|
2020-04-18 18:11:21 +10:00
|
|
|
function handleMouseDown(event) {
|
2020-04-18 18:54:13 +10:00
|
|
|
setIsMouseDown(true);
|
2020-04-19 00:24:06 +10:00
|
|
|
if (selectedTool === "brush") {
|
|
|
|
|
const position = getMousePosition(event);
|
2020-04-19 13:33:31 +10:00
|
|
|
setBrushPoints([position]);
|
2020-04-19 00:24:06 +10:00
|
|
|
}
|
2020-04-18 18:11:21 +10:00
|
|
|
}
|
|
|
|
|
|
2020-04-19 00:24:06 +10:00
|
|
|
const [mousePosition, setMousePosition] = useState({ x: 0, y: 0 });
|
2020-04-18 18:11:21 +10:00
|
|
|
function handleMouseMove(event) {
|
2020-04-19 00:24:06 +10:00
|
|
|
const position = getMousePosition(event);
|
|
|
|
|
if (selectedTool === "erase") {
|
|
|
|
|
setMousePosition(position);
|
|
|
|
|
}
|
|
|
|
|
if (isMouseDown && selectedTool === "brush") {
|
|
|
|
|
setMousePosition(position);
|
2020-04-19 13:33:31 +10:00
|
|
|
setBrushPoints((prevPoints) => [...prevPoints, position]);
|
2020-04-18 18:11:21 +10:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function handleMouseUp(event) {
|
2020-04-18 18:54:13 +10:00
|
|
|
setIsMouseDown(false);
|
2020-04-19 00:24:06 +10:00
|
|
|
if (selectedTool === "brush") {
|
2020-04-19 13:33:31 +10:00
|
|
|
const simplifiedPoints = simplify(brushPoints, 0.001);
|
|
|
|
|
onShapeAdd({ id: shortid.generate(), points: simplifiedPoints });
|
|
|
|
|
setBrushPoints([]);
|
|
|
|
|
}
|
|
|
|
|
if (selectedTool === "erase" && hoveredShapeRef.current) {
|
|
|
|
|
onShapeRemove(hoveredShapeRef.current.id);
|
2020-04-19 00:24:06 +10:00
|
|
|
}
|
2020-04-18 18:11:21 +10:00
|
|
|
}
|
|
|
|
|
|
2020-04-19 13:33:31 +10:00
|
|
|
const hoveredShapeRef = useRef(null);
|
2020-04-18 18:54:13 +10:00
|
|
|
useEffect(() => {
|
2020-04-19 13:33:31 +10:00
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-18 18:54:13 +10:00
|
|
|
const canvas = canvasRef.current;
|
|
|
|
|
if (canvas) {
|
|
|
|
|
const context = canvas.getContext("2d");
|
|
|
|
|
|
|
|
|
|
context.clearRect(0, 0, width, height);
|
2020-04-19 13:33:31 +10:00
|
|
|
let hoveredShape = null;
|
|
|
|
|
for (let shape of shapes) {
|
|
|
|
|
const path = pointsToPath(shape.points);
|
|
|
|
|
// Detect hover
|
2020-04-19 00:24:06 +10:00
|
|
|
if (selectedTool === "erase") {
|
|
|
|
|
if (
|
|
|
|
|
context.isPointInPath(
|
|
|
|
|
path,
|
|
|
|
|
mousePosition.x * width,
|
|
|
|
|
mousePosition.y * height
|
|
|
|
|
)
|
|
|
|
|
) {
|
2020-04-19 13:33:31 +10:00
|
|
|
hoveredShape = shape;
|
2020-04-19 00:24:06 +10:00
|
|
|
}
|
|
|
|
|
}
|
2020-04-19 13:33:31 +10:00
|
|
|
drawPath(path, "#000000", context);
|
2020-04-19 00:24:06 +10:00
|
|
|
}
|
2020-04-19 13:33:31 +10:00
|
|
|
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);
|
2020-04-18 18:54:13 +10:00
|
|
|
}
|
2020-04-19 13:33:31 +10:00
|
|
|
hoveredShapeRef.current = hoveredShape;
|
2020-04-18 18:54:13 +10:00
|
|
|
}
|
2020-04-19 13:33:31 +10:00
|
|
|
}, [
|
|
|
|
|
shapes,
|
|
|
|
|
width,
|
|
|
|
|
height,
|
|
|
|
|
mousePosition,
|
|
|
|
|
isMouseDown,
|
|
|
|
|
selectedTool,
|
|
|
|
|
brushPoints,
|
|
|
|
|
]);
|
2020-04-18 18:54:13 +10:00
|
|
|
|
2020-04-18 18:11:21 +10:00
|
|
|
return (
|
|
|
|
|
<div
|
|
|
|
|
style={{ position: "absolute", top: 0, left: 0, right: 0, bottom: 0 }}
|
|
|
|
|
ref={containerRef}
|
|
|
|
|
onMouseDown={handleMouseDown}
|
|
|
|
|
onMouseMove={handleMouseMove}
|
|
|
|
|
onMouseUp={handleMouseUp}
|
2020-04-18 18:54:13 +10:00
|
|
|
>
|
|
|
|
|
<canvas
|
|
|
|
|
ref={canvasRef}
|
|
|
|
|
width={width}
|
|
|
|
|
height={height}
|
|
|
|
|
style={{ width: "100%", height: "100%" }}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
2020-04-18 18:11:21 +10:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default MapDrawing;
|