Files
grungnet/src/components/map/MapFog.js

221 lines
5.2 KiB
JavaScript
Raw Normal View History

2020-05-22 17:22:32 +10:00
import React, { useContext, useEffect, useState } from "react";
import shortid from "shortid";
2020-05-22 17:22:32 +10:00
import { Group, Line } from "react-konva";
import useImage from "use-image";
import diagonalPattern from "../../images/DiagonalPattern.png";
import MapInteractionContext from "../../contexts/MapInteractionContext";
import { compare as comparePoints } from "../../helpers/vector2";
import {
getBrushPositionForTool,
simplifyPoints,
2020-05-22 17:22:32 +10:00
getStrokeWidth,
} from "../../helpers/drawing";
2020-05-22 17:22:32 +10:00
import colors from "../../helpers/colors";
2020-04-29 20:40:34 +10:00
function MapFog({
shapes,
onShapeAdd,
onShapeRemove,
2020-04-29 20:40:34 +10:00
onShapeEdit,
2020-05-22 17:22:32 +10:00
selectedToolId,
selectedToolSettings,
gridSize,
}) {
2020-05-22 17:22:32 +10:00
const {
stageDragState,
mapDragPosition,
stageScale,
mapWidth,
mapHeight,
} = useContext(MapInteractionContext);
const [drawingShape, setDrawingShape] = useState(null);
2020-05-22 17:22:32 +10:00
const isEditing = selectedToolId === "fog";
const shouldHover =
isEditing &&
2020-05-22 17:22:32 +10:00
(selectedToolSettings.type === "toggle" ||
selectedToolSettings.type === "remove");
2020-05-22 17:22:32 +10:00
const [patternImage] = useImage(diagonalPattern);
useEffect(() => {
if (!isEditing) {
return;
}
2020-05-22 17:22:32 +10:00
function startShape() {
const brushPosition = getBrushPositionForTool(
mapDragPosition,
selectedToolId,
selectedToolSettings,
gridSize,
shapes
);
if (selectedToolSettings.type === "add") {
setDrawingShape({
type: "fog",
data: { points: [brushPosition] },
strokeWidth: 0.5,
color: "black",
blend: false,
id: shortid.generate(),
visible: true,
});
}
}
2020-05-22 17:22:32 +10:00
function continueShape() {
const brushPosition = getBrushPositionForTool(
2020-05-22 17:22:32 +10:00
mapDragPosition,
selectedToolId,
selectedToolSettings,
gridSize,
shapes
);
2020-05-22 17:22:32 +10:00
if (selectedToolSettings.type === "add") {
setDrawingShape((prevShape) => {
const prevPoints = prevShape.data.points;
if (
comparePoints(
prevPoints[prevPoints.length - 1],
brushPosition,
0.001
)
) {
return prevShape;
}
return {
...prevShape,
data: { points: [...prevPoints, brushPosition] },
};
});
}
}
2020-05-22 17:22:32 +10:00
function endShape() {
if (selectedToolSettings.type === "add" && drawingShape) {
if (drawingShape.data.points.length > 1) {
const shape = {
...drawingShape,
data: {
points: simplifyPoints(
drawingShape.data.points,
gridSize,
// Downscale fog as smoothing doesn't currently work with edge snapping
stageScale / 2
),
},
};
onShapeAdd(shape);
}
}
setDrawingShape(null);
}
switch (stageDragState) {
case "first":
startShape();
return;
case "dragging":
continueShape();
return;
case "last":
endShape();
return;
default:
return;
}
2020-05-22 17:22:32 +10:00
}, [
stageDragState,
mapDragPosition,
selectedToolId,
selectedToolSettings,
isEditing,
gridSize,
stageScale,
onShapeAdd,
shapes,
drawingShape,
]);
function handleShapeClick(_, shape) {
if (!isEditing) {
return;
}
2020-05-22 17:22:32 +10:00
if (selectedToolSettings.type === "remove") {
onShapeRemove(shape.id);
} else if (selectedToolSettings.type === "toggle") {
onShapeEdit({ ...shape, visible: !shape.visible });
}
2020-05-22 17:22:32 +10:00
}
2020-05-22 17:22:32 +10:00
function handleShapeMouseOver(event, shape) {
if (shouldHover) {
const path = event.target;
if (shape.visible) {
const hoverColor = "#BB99FF";
path.fill(hoverColor);
} else {
path.opacity(1);
2020-04-29 20:40:34 +10:00
}
2020-05-22 17:22:32 +10:00
path.getLayer().draw();
}
}
2020-05-22 17:22:32 +10:00
function handleShapeMouseOut(event, shape) {
if (shouldHover) {
const path = event.target;
if (shape.visible) {
const color = colors[shape.color] || shape.color;
path.fill(color);
2020-04-29 20:40:34 +10:00
} else {
2020-05-22 17:22:32 +10:00
path.opacity(0.5);
}
2020-05-22 17:22:32 +10:00
path.getLayer().draw();
}
2020-05-22 17:22:32 +10:00
}
2020-05-22 17:22:32 +10:00
function renderShape(shape) {
return (
<Line
key={shape.id}
onMouseOver={(e) => handleShapeMouseOver(e, shape)}
onMouseOut={(e) => handleShapeMouseOut(e, shape)}
onClick={(e) => handleShapeClick(e, shape)}
points={shape.data.points.reduce(
(acc, point) => [...acc, point.x * mapWidth, point.y * mapHeight],
[]
)}
stroke={colors[shape.color] || shape.color}
fill={colors[shape.color] || shape.color}
closed
lineCap="round"
strokeWidth={getStrokeWidth(
shape.strokeWidth,
gridSize,
mapWidth,
mapHeight
)}
visible={isEditing || shape.visible}
opacity={isEditing ? 0.5 : 1}
fillPatternImage={patternImage}
fillPriority={isEditing && !shape.visible ? "pattern" : "color"}
/>
2020-05-22 17:22:32 +10:00
);
}
return (
<Group>
{shapes.map(renderShape)}
{drawingShape && renderShape(drawingShape)}
</Group>
);
}
export default MapFog;