Added fog polygon tool and changed fog interaction method

This commit is contained in:
Mitchell McCaffrey
2020-06-19 18:04:58 +10:00
parent 5a93d9a526
commit aa4ba33a0b
11 changed files with 319 additions and 175 deletions

View File

@@ -1,4 +1,4 @@
import React, { useContext, useState, useCallback } from "react";
import React, { useContext, useState, useEffect } from "react";
import shortid from "shortid";
import { Group } from "react-konva";
import useImage from "use-image";
@@ -6,6 +6,7 @@ import useImage from "use-image";
import diagonalPattern from "../../images/DiagonalPattern.png";
import MapInteractionContext from "../../contexts/MapInteractionContext";
import MapStageContext from "../../contexts/MapStageContext";
import { compare as comparePoints } from "../../helpers/vector2";
import {
@@ -14,8 +15,10 @@ import {
getStrokeWidth,
} from "../../helpers/drawing";
import colors from "../../helpers/colors";
import useMapBrush from "../../helpers/useMapBrush";
import { HoleyLine } from "../../helpers/konva";
import {
HoleyLine,
getRelativePointerPositionNormalized,
} from "../../helpers/konva";
function MapFog({
shapes,
@@ -28,6 +31,7 @@ function MapFog({
gridSize,
}) {
const { stageScale, mapWidth, mapHeight } = useContext(MapInteractionContext);
const mapStageRef = useContext(MapStageContext);
const [drawingShape, setDrawingShape] = useState(null);
const [isBrushDown, setIsBrushDown] = useState(false);
const [editingShapes, setEditingShapes] = useState([]);
@@ -40,149 +44,209 @@ function MapFog({
const [patternImage] = useImage(diagonalPattern);
const handleBrushUp = useCallback(() => {
setIsBrushDown(false);
if (editingShapes.length > 0) {
if (selectedToolSettings.type === "remove") {
onShapesRemove(editingShapes.map((shape) => shape.id));
} else if (selectedToolSettings.type === "toggle") {
onShapesEdit(
editingShapes.map((shape) => ({ ...shape, visible: !shape.visible }))
);
}
setEditingShapes([]);
useEffect(() => {
if (!isEditing) {
return;
}
}, [editingShapes, onShapesRemove, onShapesEdit, selectedToolSettings]);
const handleShapeDraw = useCallback(
(brushState, mapBrushPosition) => {
function startShape() {
const brushPosition = getBrushPositionForTool(
mapBrushPosition,
selectedToolId,
selectedToolSettings,
gridSize,
shapes
);
if (
selectedToolSettings.type === "add" ||
selectedToolSettings.type === "subtract"
) {
setDrawingShape({
type: "fog",
data: { points: [brushPosition], holes: [] },
strokeWidth: 0.5,
color: selectedToolSettings.type === "add" ? "black" : "red",
blend: false,
id: shortid.generate(),
visible: true,
});
}
setIsBrushDown(true);
const mapStage = mapStageRef.current;
function getBrushPosition() {
const mapImage = mapStage.findOne("#mapImage");
return getBrushPositionForTool(
getRelativePointerPositionNormalized(mapImage),
selectedToolId,
selectedToolSettings,
gridSize,
shapes
);
}
function handleBrushDown() {
const brushPosition = getBrushPosition();
if (selectedToolSettings.type === "brush") {
setDrawingShape({
type: "fog",
data: {
points: [brushPosition],
holes: [],
},
strokeWidth: 0.5,
color: selectedToolSettings.useFogSubtract ? "red" : "black",
blend: false,
id: shortid.generate(),
visible: true,
});
}
setIsBrushDown(true);
}
function continueShape() {
const brushPosition = getBrushPositionForTool(
mapBrushPosition,
selectedToolId,
selectedToolSettings,
gridSize,
shapes
);
if (
selectedToolSettings.type === "add" ||
selectedToolSettings.type === "subtract"
) {
setDrawingShape((prevShape) => {
const prevPoints = prevShape.data.points;
if (
comparePoints(
prevPoints[prevPoints.length - 1],
brushPosition,
0.001
)
) {
return prevShape;
}
return {
...prevShape,
data: {
...prevShape.data,
points: [...prevPoints, brushPosition],
},
};
});
}
function handleBrushMove() {
if (
selectedToolSettings.type === "brush" &&
isBrushDown &&
drawingShape
) {
const brushPosition = getBrushPosition();
setDrawingShape((prevShape) => {
const prevPoints = prevShape.data.points;
if (
comparePoints(
prevPoints[prevPoints.length - 1],
brushPosition,
0.001
)
) {
return prevShape;
}
return {
...prevShape,
data: {
...prevShape.data,
points: [...prevPoints, brushPosition],
},
};
});
}
if (selectedToolSettings.type === "polygon" && drawingShape) {
const brushPosition = getBrushPosition();
setDrawingShape((prevShape) => {
return {
...prevShape,
data: {
...prevShape.data,
points: [...prevShape.data.points.slice(0, -1), brushPosition],
},
};
});
}
}
function endShape() {
if (selectedToolSettings.type === "add" && drawingShape) {
if (drawingShape.data.points.length > 1) {
const shape = {
...drawingShape,
data: {
...drawingShape.data,
points: simplifyPoints(
drawingShape.data.points,
gridSize,
// Downscale fog as smoothing doesn't currently work with edge snapping
stageScale / 2
),
},
};
function handleBrushUp() {
if (selectedToolSettings.type === "brush" && drawingShape) {
const subtract = selectedToolSettings.useFogSubtract;
if (drawingShape.data.points.length > 1) {
let shapeData = {};
if (subtract) {
shapeData = { id: drawingShape.id, type: drawingShape.type };
} else {
shapeData = drawingShape;
}
const shape = {
...shapeData,
data: {
...drawingShape.data,
points: simplifyPoints(
drawingShape.data.points,
gridSize,
// Downscale fog as smoothing doesn't currently work with edge snapping
stageScale / 2
),
},
};
if (subtract) {
onShapeSubtract(shape);
} else {
onShapeAdd(shape);
}
}
if (selectedToolSettings.type === "subtract" && drawingShape) {
if (drawingShape.data.points.length > 1) {
const shape = {
data: {
...drawingShape.data,
points: simplifyPoints(
drawingShape.data.points,
gridSize,
// Downscale fog as smoothing doesn't currently work with edge snapping
stageScale / 2
),
},
id: drawingShape.id,
type: drawingShape.type,
};
onShapeSubtract(shape);
}
}
setDrawingShape(null);
handleBrushUp();
}
switch (brushState) {
case "first":
startShape();
return;
case "drawing":
continueShape();
return;
case "last":
endShape();
return;
default:
return;
if (selectedToolSettings.type === "polygon") {
const brushPosition = getBrushPosition();
setDrawingShape({
type: "fog",
data: {
points: [
...(drawingShape ? drawingShape.data.points : [brushPosition]),
brushPosition,
],
holes: [],
},
strokeWidth: 0.5,
color: selectedToolSettings.useFogSubtract ? "red" : "black",
blend: false,
id: shortid.generate(),
visible: true,
});
}
},
[
selectedToolId,
selectedToolSettings,
gridSize,
stageScale,
onShapeAdd,
onShapeSubtract,
shapes,
drawingShape,
handleBrushUp,
]
);
useMapBrush(isEditing, handleShapeDraw);
if (editingShapes.length > 0) {
if (selectedToolSettings.type === "remove") {
onShapesRemove(editingShapes.map((shape) => shape.id));
} else if (selectedToolSettings.type === "toggle") {
onShapesEdit(
editingShapes.map((shape) => ({
...shape,
visible: !shape.visible,
}))
);
}
setEditingShapes([]);
}
setIsBrushDown(false);
}
function handleKeyDown(event) {
if (
event.key === "Enter" &&
selectedToolSettings.type === "polygon" &&
drawingShape
) {
const subtract = selectedToolSettings.useFogSubtract;
const data = {
...drawingShape.data,
// Remove the last point as it hasn't been placed yet
points: drawingShape.data.points.slice(0, -1),
};
if (subtract) {
onShapeSubtract({
id: drawingShape.id,
type: drawingShape.type,
data: data,
});
} else {
onShapeAdd({ ...drawingShape, data: data });
}
setDrawingShape(null);
}
if (event.key === "Escape" && drawingShape) {
setDrawingShape(null);
}
}
mapStage.on("mousedown", handleBrushDown);
mapStage.on("mousemove", handleBrushMove);
mapStage.on("mouseup", handleBrushUp);
mapStage.container().addEventListener("keydown", handleKeyDown);
return () => {
mapStage.off("mousedown", handleBrushDown);
mapStage.off("mousemove", handleBrushMove);
mapStage.off("mouseup", handleBrushUp);
mapStage.container().removeEventListener("keydown", handleKeyDown);
};
}, [
mapStageRef,
isEditing,
drawingShape,
editingShapes,
gridSize,
isBrushDown,
onShapeAdd,
onShapeSubtract,
onShapesEdit,
onShapesRemove,
selectedToolId,
selectedToolSettings,
shapes,
stageScale,
]);
function handleShapeOver(shape, isDown) {
if (shouldHover && isDown) {