Changed map drag position to use a ref value to avoid re-renders

Added a useMapBrush helper
This commit is contained in:
Mitchell McCaffrey
2020-05-25 15:07:12 +10:00
parent 8932ceb1e3
commit b0c1dcf9dd
5 changed files with 285 additions and 224 deletions
+108 -115
View File
@@ -1,4 +1,4 @@
import React, { useContext, useEffect, useState } from "react";
import React, { useContext, useState, useCallback } from "react";
import shortid from "shortid";
import { Group, Line, Rect, Circle } from "react-konva";
@@ -14,6 +14,7 @@ import {
} from "../../helpers/drawing";
import colors from "../../helpers/colors";
import useMapBrush from "../../helpers/useMapBrush";
function MapDrawing({
shapes,
@@ -23,13 +24,7 @@ function MapDrawing({
selectedToolSettings,
gridSize,
}) {
const {
stageDragState,
mapDragPosition,
stageScale,
mapWidth,
mapHeight,
} = useContext(MapInteractionContext);
const { stageScale, mapWidth, mapHeight } = useContext(MapInteractionContext);
const [drawingShape, setDrawingShape] = useState(null);
const shouldHover = selectedToolId === "erase";
@@ -38,122 +33,120 @@ function MapDrawing({
selectedToolId === "shape" ||
selectedToolId === "erase";
useEffect(() => {
if (!isEditing) {
return;
}
function startShape() {
const brushPosition = getBrushPositionForTool(
mapDragPosition,
selectedToolId,
selectedToolSettings,
gridSize,
shapes
);
const commonShapeData = {
color: selectedToolSettings && selectedToolSettings.color,
blend: selectedToolSettings && selectedToolSettings.useBlending,
id: shortid.generate(),
};
if (selectedToolId === "brush") {
setDrawingShape({
type: "path",
pathType: selectedToolSettings.type,
data: { points: [brushPosition] },
strokeWidth: selectedToolSettings.type === "stroke" ? 1 : 0,
...commonShapeData,
});
} else if (selectedToolId === "shape") {
setDrawingShape({
type: "shape",
shapeType: selectedToolSettings.type,
data: getDefaultShapeData(selectedToolSettings.type, brushPosition),
strokeWidth: 0,
...commonShapeData,
});
const handleShapeDraw = useCallback(
(brushState, mapBrushPosition) => {
function startShape() {
const brushPosition = getBrushPositionForTool(
mapBrushPosition,
selectedToolId,
selectedToolSettings,
gridSize,
shapes
);
const commonShapeData = {
color: selectedToolSettings && selectedToolSettings.color,
blend: selectedToolSettings && selectedToolSettings.useBlending,
id: shortid.generate(),
};
if (selectedToolId === "brush") {
setDrawingShape({
type: "path",
pathType: selectedToolSettings.type,
data: { points: [brushPosition] },
strokeWidth: selectedToolSettings.type === "stroke" ? 1 : 0,
...commonShapeData,
});
} else if (selectedToolId === "shape") {
setDrawingShape({
type: "shape",
shapeType: selectedToolSettings.type,
data: getDefaultShapeData(selectedToolSettings.type, brushPosition),
strokeWidth: 0,
...commonShapeData,
});
}
}
}
function continueShape() {
const brushPosition = getBrushPositionForTool(
mapDragPosition,
selectedToolId,
selectedToolSettings,
gridSize,
shapes
);
if (selectedToolId === "brush") {
setDrawingShape((prevShape) => {
const prevPoints = prevShape.data.points;
if (
comparePoints(
prevPoints[prevPoints.length - 1],
brushPosition,
0.001
)
) {
return prevShape;
}
const simplified = simplifyPoints(
[...prevPoints, brushPosition],
gridSize,
stageScale
);
return {
function continueShape() {
const brushPosition = getBrushPositionForTool(
mapBrushPosition,
selectedToolId,
selectedToolSettings,
gridSize,
shapes
);
if (selectedToolId === "brush") {
setDrawingShape((prevShape) => {
const prevPoints = prevShape.data.points;
if (
comparePoints(
prevPoints[prevPoints.length - 1],
brushPosition,
0.001
)
) {
return prevShape;
}
const simplified = simplifyPoints(
[...prevPoints, brushPosition],
gridSize,
stageScale
);
return {
...prevShape,
data: { points: simplified },
};
});
} else if (selectedToolId === "shape") {
setDrawingShape((prevShape) => ({
...prevShape,
data: { points: simplified },
};
});
} else if (selectedToolId === "shape") {
setDrawingShape((prevShape) => ({
...prevShape,
data: getUpdatedShapeData(
prevShape.shapeType,
prevShape.data,
brushPosition,
gridSize
),
}));
data: getUpdatedShapeData(
prevShape.shapeType,
prevShape.data,
brushPosition,
gridSize
),
}));
}
}
}
function endShape() {
if (selectedToolId === "brush" && drawingShape) {
if (drawingShape.data.points.length > 1) {
function endShape() {
if (selectedToolId === "brush" && drawingShape) {
if (drawingShape.data.points.length > 1) {
onShapeAdd(drawingShape);
}
} else if (selectedToolId === "shape" && drawingShape) {
onShapeAdd(drawingShape);
}
} else if (selectedToolId === "shape" && drawingShape) {
onShapeAdd(drawingShape);
setDrawingShape(null);
}
setDrawingShape(null);
}
switch (stageDragState) {
case "first":
startShape();
return;
case "dragging":
continueShape();
return;
case "last":
endShape();
return;
default:
return;
}
}, [
stageDragState,
mapDragPosition,
selectedToolId,
selectedToolSettings,
isEditing,
gridSize,
stageScale,
onShapeAdd,
shapes,
drawingShape,
]);
switch (brushState) {
case "first":
startShape();
return;
case "drawing":
continueShape();
return;
case "last":
endShape();
return;
default:
return;
}
},
[
selectedToolId,
selectedToolSettings,
gridSize,
stageScale,
onShapeAdd,
shapes,
drawingShape,
]
);
useMapBrush(isEditing, handleShapeDraw);
function handleShapeClick(_, shape) {
if (selectedToolId === "erase") {
+97 -104
View File
@@ -1,4 +1,4 @@
import React, { useContext, useEffect, useState } from "react";
import React, { useContext, useState, useCallback } from "react";
import shortid from "shortid";
import { Group, Line } from "react-konva";
import useImage from "use-image";
@@ -15,6 +15,7 @@ import {
} from "../../helpers/drawing";
import colors from "../../helpers/colors";
import useMapBrush from "../../helpers/useMapBrush";
function MapFog({
shapes,
@@ -25,13 +26,7 @@ function MapFog({
selectedToolSettings,
gridSize,
}) {
const {
stageDragState,
mapDragPosition,
stageScale,
mapWidth,
mapHeight,
} = useContext(MapInteractionContext);
const { stageScale, mapWidth, mapHeight } = useContext(MapInteractionContext);
const [drawingShape, setDrawingShape] = useState(null);
const isEditing = selectedToolId === "fog";
@@ -42,105 +37,103 @@ function MapFog({
const [patternImage] = useImage(diagonalPattern);
useEffect(() => {
if (!isEditing) {
return;
}
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,
});
}
}
function continueShape() {
const brushPosition = getBrushPositionForTool(
mapDragPosition,
selectedToolId,
selectedToolSettings,
gridSize,
shapes
);
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] },
};
});
}
}
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);
const handleShapeDraw = useCallback(
(brushState, mapBrushPosition) => {
function startShape() {
const brushPosition = getBrushPositionForTool(
mapBrushPosition,
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,
});
}
}
setDrawingShape(null);
}
switch (stageDragState) {
case "first":
startShape();
return;
case "dragging":
continueShape();
return;
case "last":
endShape();
return;
default:
return;
}
}, [
stageDragState,
mapDragPosition,
selectedToolId,
selectedToolSettings,
isEditing,
gridSize,
stageScale,
onShapeAdd,
shapes,
drawingShape,
]);
function continueShape() {
const brushPosition = getBrushPositionForTool(
mapBrushPosition,
selectedToolId,
selectedToolSettings,
gridSize,
shapes
);
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] },
};
});
}
}
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 (brushState) {
case "first":
startShape();
return;
case "drawing":
continueShape();
return;
case "last":
endShape();
return;
default:
return;
}
},
[
selectedToolId,
selectedToolSettings,
gridSize,
stageScale,
onShapeAdd,
shapes,
drawingShape,
]
);
useMapBrush(isEditing, handleShapeDraw);
function handleShapeClick(_, shape) {
if (!isEditing) {
+7 -5
View File
@@ -29,12 +29,12 @@ function MapInteraction({ map, children, controls, selectedToolId }) {
// "none" | "first" | "dragging" | "last"
const [stageDragState, setStageDragState] = useState("none");
const [preventMapInteraction, setPreventMapInteraction] = useState(false);
const [mapDragPosition, setMapDragPosition] = useState({ x: 0, y: 0 });
const stageWidthRef = useRef(stageWidth);
const stageHeightRef = useRef(stageHeight);
// Avoid state udpates when panning the map by using a ref and updating the konva element directly
const stageTranslateRef = useRef({ x: 0, y: 0 });
const mapDragPositionRef = useRef({ x: 0, y: 0 });
useEffect(() => {
const layer = mapLayerRef.current;
@@ -103,9 +103,11 @@ function MapInteraction({ map, children, controls, selectedToolId }) {
layer.y(newTranslate.y);
layer.draw();
stageTranslateRef.current = newTranslate;
} else {
setMapDragPosition(getMapDragPosition(xy));
setStageDragState(first ? "first" : last ? "last" : "dragging");
}
mapDragPositionRef.current = getMapDragPosition(xy);
const newDragState = first ? "first" : last ? "last" : "dragging";
if (stageDragState !== newDragState) {
setStageDragState(newDragState);
}
},
onDragEnd: () => {
@@ -153,7 +155,7 @@ function MapInteraction({ map, children, controls, selectedToolId }) {
setPreventMapInteraction,
mapWidth,
mapHeight,
mapDragPosition,
mapDragPositionRef,
};
return (