Moved back to drag events for map and fog drawing
Moved to an event driven model for dragging
This commit is contained in:
parent
afb22c7a73
commit
9a4d047cd5
@ -25,7 +25,9 @@ function MapDrawing({
|
||||
selectedToolSettings,
|
||||
gridSize,
|
||||
}) {
|
||||
const { stageScale, mapWidth, mapHeight } = useContext(MapInteractionContext);
|
||||
const { stageScale, mapWidth, mapHeight, interactionEmitter } = useContext(
|
||||
MapInteractionContext
|
||||
);
|
||||
const mapStageRef = useContext(MapStageContext);
|
||||
const [drawingShape, setDrawingShape] = useState(null);
|
||||
const [isBrushDown, setIsBrushDown] = useState(false);
|
||||
@ -145,14 +147,14 @@ function MapDrawing({
|
||||
setIsBrushDown(false);
|
||||
}
|
||||
|
||||
mapStage.on("mousedown touchstart", handleBrushDown);
|
||||
mapStage.on("mousemove touchmove", handleBrushMove);
|
||||
mapStage.on("mouseup touchend", handleBrushUp);
|
||||
interactionEmitter.on("dragStart", handleBrushDown);
|
||||
interactionEmitter.on("drag", handleBrushMove);
|
||||
interactionEmitter.on("dragEnd", handleBrushUp);
|
||||
|
||||
return () => {
|
||||
mapStage.off("mousedown touchstart", handleBrushDown);
|
||||
mapStage.off("mousemove touchmove", handleBrushMove);
|
||||
mapStage.off("mouseup touchend", handleBrushUp);
|
||||
interactionEmitter.off("dragStart", handleBrushDown);
|
||||
interactionEmitter.off("drag", handleBrushMove);
|
||||
interactionEmitter.off("dragEnd", handleBrushUp);
|
||||
};
|
||||
}, [
|
||||
drawingShape,
|
||||
@ -169,6 +171,7 @@ function MapDrawing({
|
||||
selectedToolSettings,
|
||||
shapes,
|
||||
stageScale,
|
||||
interactionEmitter,
|
||||
]);
|
||||
|
||||
function handleShapeOver(shape, isDown) {
|
||||
@ -188,6 +191,7 @@ function MapDrawing({
|
||||
onTouchStart: () => handleShapeOver(shape, true),
|
||||
fill: colors[shape.color] || shape.color,
|
||||
opacity: shape.blend ? 0.5 : 1,
|
||||
id: shape.id,
|
||||
};
|
||||
if (shape.type === "path") {
|
||||
return (
|
||||
|
@ -31,7 +31,9 @@ function MapFog({
|
||||
selectedToolSettings,
|
||||
gridSize,
|
||||
}) {
|
||||
const { stageScale, mapWidth, mapHeight } = useContext(MapInteractionContext);
|
||||
const { stageScale, mapWidth, mapHeight, interactionEmitter } = useContext(
|
||||
MapInteractionContext
|
||||
);
|
||||
const mapStageRef = useContext(MapStageContext);
|
||||
const [drawingShape, setDrawingShape] = useState(null);
|
||||
const [isBrushDown, setIsBrushDown] = useState(false);
|
||||
@ -109,18 +111,6 @@ function MapFog({
|
||||
};
|
||||
});
|
||||
}
|
||||
if (selectedToolSettings.type === "polygon" && drawingShape) {
|
||||
const brushPosition = getBrushPosition();
|
||||
setDrawingShape((prevShape) => {
|
||||
return {
|
||||
...prevShape,
|
||||
data: {
|
||||
...prevShape.data,
|
||||
points: [...prevShape.data.points.slice(0, -1), brushPosition],
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function handleBrushUp() {
|
||||
@ -152,29 +142,10 @@ function MapFog({
|
||||
onShapeAdd(shape);
|
||||
}
|
||||
}
|
||||
|
||||
setDrawingShape(null);
|
||||
}
|
||||
|
||||
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,
|
||||
});
|
||||
}
|
||||
|
||||
// Erase
|
||||
if (editingShapes.length > 0) {
|
||||
if (selectedToolSettings.type === "remove") {
|
||||
onShapesRemove(editingShapes.map((shape) => shape.id));
|
||||
@ -192,14 +163,69 @@ function MapFog({
|
||||
setIsBrushDown(false);
|
||||
}
|
||||
|
||||
mapStage.on("mousedown touchstart", handleBrushDown);
|
||||
mapStage.on("mousemove touchmove", handleBrushMove);
|
||||
mapStage.on("mouseup touchend", handleBrushUp);
|
||||
function handlePolygonClick() {
|
||||
if (selectedToolSettings.type === "polygon") {
|
||||
const brushPosition = getBrushPosition();
|
||||
setDrawingShape((prevDrawingShape) => {
|
||||
if (prevDrawingShape) {
|
||||
return {
|
||||
...prevDrawingShape,
|
||||
data: {
|
||||
...prevDrawingShape.data,
|
||||
points: [...prevDrawingShape.data.points, brushPosition],
|
||||
},
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
type: "fog",
|
||||
data: {
|
||||
points: [brushPosition, brushPosition],
|
||||
holes: [],
|
||||
},
|
||||
strokeWidth: 0.5,
|
||||
color: selectedToolSettings.useFogSubtract ? "red" : "black",
|
||||
blend: false,
|
||||
id: shortid.generate(),
|
||||
visible: true,
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function handlePolygonMove() {
|
||||
if (selectedToolSettings.type === "polygon" && drawingShape) {
|
||||
const brushPosition = getBrushPosition();
|
||||
setDrawingShape((prevShape) => {
|
||||
if (!prevShape) {
|
||||
return;
|
||||
}
|
||||
return {
|
||||
...prevShape,
|
||||
data: {
|
||||
...prevShape.data,
|
||||
points: [...prevShape.data.points.slice(0, -1), brushPosition],
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
interactionEmitter.on("dragStart", handleBrushDown);
|
||||
interactionEmitter.on("drag", handleBrushMove);
|
||||
interactionEmitter.on("dragEnd", handleBrushUp);
|
||||
// Use mouse events for polygon and erase to allow for single clicks
|
||||
mapStage.on("mousedown touchstart", handlePolygonMove);
|
||||
mapStage.on("mousemove touchmove", handlePolygonMove);
|
||||
mapStage.on("click tap", handlePolygonClick);
|
||||
|
||||
return () => {
|
||||
mapStage.off("mousedown touchstart", handleBrushDown);
|
||||
mapStage.off("mousemove touchmove", handleBrushMove);
|
||||
mapStage.off("mouseup touchend", handleBrushUp);
|
||||
interactionEmitter.off("dragStart", handleBrushDown);
|
||||
interactionEmitter.off("drag", handleBrushMove);
|
||||
interactionEmitter.off("dragEnd", handleBrushUp);
|
||||
mapStage.off("mousedown touchstart", handlePolygonMove);
|
||||
mapStage.off("mousemove touchmove", handlePolygonMove);
|
||||
mapStage.off("click tap", handlePolygonClick);
|
||||
};
|
||||
}, [
|
||||
mapStageRef,
|
||||
@ -216,6 +242,7 @@ function MapFog({
|
||||
selectedToolSettings,
|
||||
shapes,
|
||||
stageScale,
|
||||
interactionEmitter,
|
||||
]);
|
||||
|
||||
const finishDrawingPolygon = useCallback(() => {
|
||||
@ -317,15 +344,16 @@ function MapFog({
|
||||
if (shape.data.points.length === 0) {
|
||||
return;
|
||||
}
|
||||
const isCross = shape.data.points.length < 4;
|
||||
return (
|
||||
<Tick
|
||||
x={shape.data.points[0].x * mapWidth}
|
||||
y={shape.data.points[0].y * mapHeight}
|
||||
scale={1 / stageScale}
|
||||
cross={shape.data.points.length < 4}
|
||||
onClick={() => {
|
||||
// Check that there is enough points after clicking
|
||||
if (shape.data.points.length < 5) {
|
||||
cross={isCross}
|
||||
onClick={(e) => {
|
||||
e.cancelBubble = true;
|
||||
if (isCross) {
|
||||
setDrawingShape(null);
|
||||
} else {
|
||||
finishDrawingPolygon();
|
||||
|
@ -4,6 +4,7 @@ import { useGesture } from "react-use-gesture";
|
||||
import ReactResizeDetector from "react-resize-detector";
|
||||
import useImage from "use-image";
|
||||
import { Stage, Layer, Image } from "react-konva";
|
||||
import { EventEmitter } from "events";
|
||||
|
||||
import usePreventOverscroll from "../../helpers/usePreventOverscroll";
|
||||
import useDataSource from "../../helpers/useDataSource";
|
||||
@ -34,15 +35,12 @@ function MapInteraction({
|
||||
const [stageWidth, setStageWidth] = useState(1);
|
||||
const [stageHeight, setStageHeight] = useState(1);
|
||||
const [stageScale, setStageScale] = useState(1);
|
||||
// "none" | "first" | "dragging" | "last"
|
||||
const [stageDragState, setStageDragState] = useState("none");
|
||||
const [preventMapInteraction, setPreventMapInteraction] = useState(false);
|
||||
|
||||
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 });
|
||||
|
||||
// Reset transform when map changes
|
||||
useEffect(() => {
|
||||
@ -62,30 +60,13 @@ function MapInteraction({
|
||||
}
|
||||
}, [map]);
|
||||
|
||||
// Convert a client space XY to be normalized to the map image
|
||||
function getMapDragPosition(xy) {
|
||||
const [x, y] = xy;
|
||||
const container = containerRef.current;
|
||||
const mapImage = mapImageRef.current;
|
||||
if (container && mapImage) {
|
||||
const containerRect = container.getBoundingClientRect();
|
||||
const mapRect = mapImage.getClientRect();
|
||||
|
||||
const offsetX = x - containerRect.left - mapRect.x;
|
||||
const offsetY = y - containerRect.top - mapRect.y;
|
||||
|
||||
const normalizedX = offsetX / mapRect.width;
|
||||
const normalizedY = offsetY / mapRect.height;
|
||||
|
||||
return { x: normalizedX, y: normalizedY };
|
||||
}
|
||||
}
|
||||
|
||||
const pinchPreviousDistanceRef = useRef();
|
||||
const pinchPreviousOriginRef = useRef();
|
||||
const isInteractingWithCanvas = useRef(false);
|
||||
const previousSelectedToolRef = useRef(selectedToolId);
|
||||
|
||||
const [interactionEmitter] = useState(new EventEmitter());
|
||||
|
||||
const bind = useGesture({
|
||||
onWheelStart: ({ event }) => {
|
||||
isInteractingWithCanvas.current =
|
||||
@ -168,15 +149,14 @@ function MapInteraction({
|
||||
layer.draw();
|
||||
stageTranslateRef.current = newTranslate;
|
||||
}
|
||||
mapDragPositionRef.current = getMapDragPosition(xy);
|
||||
const newDragState = first ? "first" : last ? "last" : "dragging";
|
||||
if (stageDragState !== newDragState) {
|
||||
setStageDragState(newDragState);
|
||||
if (first) {
|
||||
interactionEmitter.emit("dragStart");
|
||||
} else if (last) {
|
||||
interactionEmitter.emit("dragEnd");
|
||||
} else {
|
||||
interactionEmitter.emit("drag");
|
||||
}
|
||||
},
|
||||
onDragEnd: () => {
|
||||
setStageDragState("none");
|
||||
},
|
||||
});
|
||||
|
||||
function handleResize(width, height) {
|
||||
@ -214,11 +194,10 @@ function MapInteraction({
|
||||
stageScale,
|
||||
stageWidth,
|
||||
stageHeight,
|
||||
stageDragState,
|
||||
setPreventMapInteraction,
|
||||
mapWidth,
|
||||
mapHeight,
|
||||
mapDragPositionRef,
|
||||
interactionEmitter,
|
||||
};
|
||||
|
||||
// Enable keyboard interaction for map stage container
|
||||
|
@ -4,11 +4,10 @@ const MapInteractionContext = React.createContext({
|
||||
stageScale: 1,
|
||||
stageWidth: 1,
|
||||
stageHeight: 1,
|
||||
stageDragState: "none",
|
||||
setPreventMapInteraction: () => {},
|
||||
mapWidth: 1,
|
||||
mapHeight: 1,
|
||||
mapDragPositionRef: { current: undefined },
|
||||
interactionEmitter: null,
|
||||
});
|
||||
export const MapInteractionProvider = MapInteractionContext.Provider;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user