Move interaction to left click and added middle click move right click pointer
This commit is contained in:
parent
659d3dd9e1
commit
5e407ba72d
@ -67,6 +67,7 @@
|
|||||||
"socket.io-msgpack-parser": "^3.0.1",
|
"socket.io-msgpack-parser": "^3.0.1",
|
||||||
"source-map-explorer": "^2.5.2",
|
"source-map-explorer": "^2.5.2",
|
||||||
"theme-ui": "^0.10.0",
|
"theme-ui": "^0.10.0",
|
||||||
|
"tiny-typed-emitter": "^2.1.0",
|
||||||
"use-image": "^1.0.8",
|
"use-image": "^1.0.8",
|
||||||
"uuid": "^8.3.2",
|
"uuid": "^8.3.2",
|
||||||
"webrtc-adapter": "^8.1.0"
|
"webrtc-adapter": "^8.1.0"
|
||||||
|
@ -102,6 +102,9 @@ function Note({
|
|||||||
}
|
}
|
||||||
|
|
||||||
function handleClick(event: Konva.KonvaEventObject<MouseEvent>) {
|
function handleClick(event: Konva.KonvaEventObject<MouseEvent>) {
|
||||||
|
if (event.evt.button !== 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (draggable) {
|
if (draggable) {
|
||||||
const noteNode = event.target;
|
const noteNode = event.target;
|
||||||
onNoteMenuOpen && onNoteMenuOpen(note.id, noteNode, true);
|
onNoteMenuOpen && onNoteMenuOpen(note.id, noteNode, true);
|
||||||
@ -111,6 +114,9 @@ function Note({
|
|||||||
// Store note pointer down time to check for a click when note is locked
|
// Store note pointer down time to check for a click when note is locked
|
||||||
const notePointerDownTimeRef = useRef<number>(0);
|
const notePointerDownTimeRef = useRef<number>(0);
|
||||||
function handlePointerDown(event: Konva.KonvaEventObject<PointerEvent>) {
|
function handlePointerDown(event: Konva.KonvaEventObject<PointerEvent>) {
|
||||||
|
if (event.evt.button !== 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (draggable) {
|
if (draggable) {
|
||||||
setPreventMapInteraction(true);
|
setPreventMapInteraction(true);
|
||||||
}
|
}
|
||||||
@ -120,6 +126,9 @@ function Note({
|
|||||||
}
|
}
|
||||||
|
|
||||||
function handlePointerUp(event: Konva.KonvaEventObject<PointerEvent>) {
|
function handlePointerUp(event: Konva.KonvaEventObject<PointerEvent>) {
|
||||||
|
if (event.evt.button !== 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (draggable) {
|
if (draggable) {
|
||||||
setPreventMapInteraction(false);
|
setPreventMapInteraction(false);
|
||||||
}
|
}
|
||||||
|
@ -197,7 +197,10 @@ function Token({
|
|||||||
setAttachmentOverCharacter(false);
|
setAttachmentOverCharacter(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleClick() {
|
function handleClick(event: Konva.KonvaEventObject<MouseEvent>) {
|
||||||
|
if (event.evt.button !== 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (selectable && draggable && transformRootRef.current) {
|
if (selectable && draggable && transformRootRef.current) {
|
||||||
onTokenMenuOpen(tokenState.id, transformRootRef.current, true);
|
onTokenMenuOpen(tokenState.id, transformRootRef.current, true);
|
||||||
}
|
}
|
||||||
@ -207,6 +210,9 @@ function Token({
|
|||||||
// Store token pointer down time to check for a click when token is locked
|
// Store token pointer down time to check for a click when token is locked
|
||||||
const tokenPointerDownTimeRef = useRef<number>(0);
|
const tokenPointerDownTimeRef = useRef<number>(0);
|
||||||
function handlePointerDown(event: Konva.KonvaEventObject<PointerEvent>) {
|
function handlePointerDown(event: Konva.KonvaEventObject<PointerEvent>) {
|
||||||
|
if (event.evt.button !== 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (draggable) {
|
if (draggable) {
|
||||||
setPreventMapInteraction(true);
|
setPreventMapInteraction(true);
|
||||||
}
|
}
|
||||||
@ -216,6 +222,9 @@ function Token({
|
|||||||
}
|
}
|
||||||
|
|
||||||
function handlePointerUp(event: Konva.KonvaEventObject<PointerEvent>) {
|
function handlePointerUp(event: Konva.KonvaEventObject<PointerEvent>) {
|
||||||
|
if (event.evt.button !== 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (draggable) {
|
if (draggable) {
|
||||||
setPreventMapInteraction(false);
|
setPreventMapInteraction(false);
|
||||||
}
|
}
|
||||||
|
@ -3,17 +3,20 @@ import { Box } from "theme-ui";
|
|||||||
import ReactResizeDetector from "react-resize-detector";
|
import ReactResizeDetector from "react-resize-detector";
|
||||||
import { Stage, Layer, Image, Group } from "react-konva";
|
import { Stage, Layer, Image, Group } from "react-konva";
|
||||||
import Konva from "konva";
|
import Konva from "konva";
|
||||||
import { EventEmitter } from "events";
|
|
||||||
|
|
||||||
import useMapImage from "../../hooks/useMapImage";
|
import useMapImage from "../../hooks/useMapImage";
|
||||||
import usePreventOverscroll from "../../hooks/usePreventOverscroll";
|
import usePreventOverscroll from "../../hooks/usePreventOverscroll";
|
||||||
import useStageInteraction from "../../hooks/useStageInteraction";
|
import useStageInteraction from "../../hooks/useStageInteraction";
|
||||||
import useImageCenter from "../../hooks/useImageCenter";
|
import useImageCenter from "../../hooks/useImageCenter";
|
||||||
|
import usePreventContextMenu from "../../hooks/usePreventContextMenu";
|
||||||
|
|
||||||
import { getGridMaxZoom } from "../../helpers/grid";
|
import { getGridMaxZoom } from "../../helpers/grid";
|
||||||
import KonvaBridge from "../../helpers/KonvaBridge";
|
import KonvaBridge from "../../helpers/KonvaBridge";
|
||||||
|
|
||||||
import { MapInteractionProvider } from "../../contexts/MapInteractionContext";
|
import {
|
||||||
|
MapInteractionEmitter,
|
||||||
|
MapInteractionProvider,
|
||||||
|
} from "../../contexts/MapInteractionContext";
|
||||||
import { useMapStage } from "../../contexts/MapStageContext";
|
import { useMapStage } from "../../contexts/MapStageContext";
|
||||||
import { GridProvider } from "../../contexts/GridContext";
|
import { GridProvider } from "../../contexts/GridContext";
|
||||||
import { useKeyboard } from "../../contexts/KeyboardContext";
|
import { useKeyboard } from "../../contexts/KeyboardContext";
|
||||||
@ -72,6 +75,7 @@ function MapInteraction({
|
|||||||
|
|
||||||
const containerRef = useRef<HTMLDivElement>(null);
|
const containerRef = useRef<HTMLDivElement>(null);
|
||||||
usePreventOverscroll(containerRef);
|
usePreventOverscroll(containerRef);
|
||||||
|
usePreventContextMenu(containerRef);
|
||||||
|
|
||||||
const [mapWidth, mapHeight] = useImageCenter(
|
const [mapWidth, mapHeight] = useImageCenter(
|
||||||
map,
|
map,
|
||||||
@ -85,8 +89,9 @@ function MapInteraction({
|
|||||||
);
|
);
|
||||||
|
|
||||||
const previousSelectedToolRef = useRef(selectedToolId);
|
const previousSelectedToolRef = useRef(selectedToolId);
|
||||||
|
const [currentMouseButtons, setCurentMouseButtons] = useState(0);
|
||||||
|
|
||||||
const [interactionEmitter] = useState(new EventEmitter());
|
const [interactionEmitter] = useState(new MapInteractionEmitter());
|
||||||
|
|
||||||
useStageInteraction(
|
useStageInteraction(
|
||||||
mapStageRef,
|
mapStageRef,
|
||||||
@ -106,13 +111,17 @@ function MapInteraction({
|
|||||||
onPinchEnd: () => {
|
onPinchEnd: () => {
|
||||||
onSelectedToolChange(previousSelectedToolRef.current);
|
onSelectedToolChange(previousSelectedToolRef.current);
|
||||||
},
|
},
|
||||||
onDrag: ({ first, last }) => {
|
onDrag: (props) => {
|
||||||
|
const { first, last, buttons } = props;
|
||||||
|
if (buttons !== currentMouseButtons) {
|
||||||
|
setCurentMouseButtons(buttons);
|
||||||
|
}
|
||||||
if (first) {
|
if (first) {
|
||||||
interactionEmitter.emit("dragStart");
|
interactionEmitter.emit("dragStart", props);
|
||||||
} else if (last) {
|
} else if (last) {
|
||||||
interactionEmitter.emit("dragEnd");
|
interactionEmitter.emit("dragEnd", props);
|
||||||
} else {
|
} else {
|
||||||
interactionEmitter.emit("drag");
|
interactionEmitter.emit("drag", props);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -143,6 +152,11 @@ function MapInteraction({
|
|||||||
useKeyboard(handleKeyDown, handleKeyUp);
|
useKeyboard(handleKeyDown, handleKeyUp);
|
||||||
|
|
||||||
function getCursorForTool(tool: MapToolId) {
|
function getCursorForTool(tool: MapToolId) {
|
||||||
|
if (currentMouseButtons === 2) {
|
||||||
|
return "crosshair";
|
||||||
|
} else if (currentMouseButtons > 2) {
|
||||||
|
return "move";
|
||||||
|
}
|
||||||
switch (tool) {
|
switch (tool) {
|
||||||
case "move":
|
case "move":
|
||||||
return "move";
|
return "move";
|
||||||
|
@ -7,6 +7,8 @@ import {
|
|||||||
useMapWidth,
|
useMapWidth,
|
||||||
useMapHeight,
|
useMapHeight,
|
||||||
useInteractionEmitter,
|
useInteractionEmitter,
|
||||||
|
leftMouseButton,
|
||||||
|
MapDragEvent,
|
||||||
} from "../../contexts/MapInteractionContext";
|
} from "../../contexts/MapInteractionContext";
|
||||||
import { useMapStage } from "../../contexts/MapStageContext";
|
import { useMapStage } from "../../contexts/MapStageContext";
|
||||||
import {
|
import {
|
||||||
@ -103,7 +105,10 @@ function DrawingTool({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleBrushDown() {
|
function handleBrushDown(props: MapDragEvent) {
|
||||||
|
if (!leftMouseButton(props)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const brushPosition = getBrushPosition();
|
const brushPosition = getBrushPosition();
|
||||||
if (!brushPosition) {
|
if (!brushPosition) {
|
||||||
return;
|
return;
|
||||||
@ -135,7 +140,10 @@ function DrawingTool({
|
|||||||
setIsBrushDown(true);
|
setIsBrushDown(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleBrushMove() {
|
function handleBrushMove(props: MapDragEvent) {
|
||||||
|
if (!leftMouseButton(props)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const brushPosition = getBrushPosition();
|
const brushPosition = getBrushPosition();
|
||||||
if (!brushPosition) {
|
if (!brushPosition) {
|
||||||
return;
|
return;
|
||||||
@ -186,7 +194,10 @@ function DrawingTool({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleBrushUp() {
|
function handleBrushUp(props: MapDragEvent) {
|
||||||
|
if (!leftMouseButton(props)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (isBrush && drawing && drawing.type === "path") {
|
if (isBrush && drawing && drawing.type === "path") {
|
||||||
if (drawing.data.points.length > 1) {
|
if (drawing.data.points.length > 1) {
|
||||||
onShapeAdd(drawing);
|
onShapeAdd(drawing);
|
||||||
|
@ -3,6 +3,7 @@ import shortid from "shortid";
|
|||||||
import { Group, Line } from "react-konva";
|
import { Group, Line } from "react-konva";
|
||||||
import useImage from "use-image";
|
import useImage from "use-image";
|
||||||
import Color from "color";
|
import Color from "color";
|
||||||
|
import Konva from "konva";
|
||||||
|
|
||||||
import diagonalPattern from "../../images/DiagonalPattern.png";
|
import diagonalPattern from "../../images/DiagonalPattern.png";
|
||||||
|
|
||||||
@ -11,6 +12,8 @@ import {
|
|||||||
useMapWidth,
|
useMapWidth,
|
||||||
useMapHeight,
|
useMapHeight,
|
||||||
useInteractionEmitter,
|
useInteractionEmitter,
|
||||||
|
MapDragEvent,
|
||||||
|
leftMouseButton,
|
||||||
} from "../../contexts/MapInteractionContext";
|
} from "../../contexts/MapInteractionContext";
|
||||||
import { useMapStage } from "../../contexts/MapStageContext";
|
import { useMapStage } from "../../contexts/MapStageContext";
|
||||||
import {
|
import {
|
||||||
@ -160,7 +163,10 @@ function FogTool({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleBrushDown() {
|
function handleBrushDown(props: MapDragEvent) {
|
||||||
|
if (!leftMouseButton(props)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (toolSettings.type === "brush") {
|
if (toolSettings.type === "brush") {
|
||||||
const brushPosition = getBrushPosition();
|
const brushPosition = getBrushPosition();
|
||||||
if (!brushPosition) {
|
if (!brushPosition) {
|
||||||
@ -203,7 +209,10 @@ function FogTool({
|
|||||||
setIsBrushDown(true);
|
setIsBrushDown(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleBrushMove() {
|
function handleBrushMove(props: MapDragEvent) {
|
||||||
|
if (!leftMouseButton(props)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (toolSettings.type === "brush" && isBrushDown && drawingShape) {
|
if (toolSettings.type === "brush" && isBrushDown && drawingShape) {
|
||||||
const brushPosition = getBrushPosition();
|
const brushPosition = getBrushPosition();
|
||||||
if (!brushPosition) {
|
if (!brushPosition) {
|
||||||
@ -258,7 +267,10 @@ function FogTool({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleBrushUp() {
|
function handleBrushUp(props: MapDragEvent) {
|
||||||
|
if (!leftMouseButton(props)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (
|
if (
|
||||||
(toolSettings.type === "brush" || toolSettings.type === "rectangle") &&
|
(toolSettings.type === "brush" || toolSettings.type === "rectangle") &&
|
||||||
drawingShape
|
drawingShape
|
||||||
@ -318,7 +330,13 @@ function FogTool({
|
|||||||
setIsBrushDown(false);
|
setIsBrushDown(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handlePointerClick() {
|
function handlePointerClick(
|
||||||
|
event: Konva.KonvaEventObject<MouseEvent | TouchEvent>
|
||||||
|
) {
|
||||||
|
// Left click only
|
||||||
|
if (event.evt instanceof MouseEvent && event.evt.button !== 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (toolSettings.type === "polygon") {
|
if (toolSettings.type === "polygon") {
|
||||||
const brushPosition = getBrushPosition();
|
const brushPosition = getBrushPosition();
|
||||||
if (brushPosition) {
|
if (brushPosition) {
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
import { Group } from "react-konva";
|
import { Group } from "react-konva";
|
||||||
|
|
||||||
import { useInteractionEmitter } from "../../contexts/MapInteractionContext";
|
import {
|
||||||
|
useInteractionEmitter,
|
||||||
|
MapDragEvent,
|
||||||
|
leftMouseButton,
|
||||||
|
} from "../../contexts/MapInteractionContext";
|
||||||
import { useMapStage } from "../../contexts/MapStageContext";
|
import { useMapStage } from "../../contexts/MapStageContext";
|
||||||
import {
|
import {
|
||||||
useGrid,
|
useGrid,
|
||||||
@ -40,8 +44,9 @@ function MeasureTool({ map, active }: MapMeasureProps) {
|
|||||||
const gridOffset = useGridOffset();
|
const gridOffset = useGridOffset();
|
||||||
|
|
||||||
const mapStageRef = useMapStage();
|
const mapStageRef = useMapStage();
|
||||||
const [drawingShapeData, setDrawingShapeData] =
|
const [drawingShapeData, setDrawingShapeData] = useState<MeasureData | null>(
|
||||||
useState<MeasureData | null>(null);
|
null
|
||||||
|
);
|
||||||
const [isBrushDown, setIsBrushDown] = useState(false);
|
const [isBrushDown, setIsBrushDown] = useState(false);
|
||||||
|
|
||||||
const gridScale = parseGridScale(active ? grid.measurement.scale : null);
|
const gridScale = parseGridScale(active ? grid.measurement.scale : null);
|
||||||
@ -75,7 +80,10 @@ function MeasureTool({ map, active }: MapMeasureProps) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleBrushDown() {
|
function handleBrushDown(props: MapDragEvent) {
|
||||||
|
if (!leftMouseButton(props)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const brushPosition = getBrushPosition();
|
const brushPosition = getBrushPosition();
|
||||||
if (!brushPosition) {
|
if (!brushPosition) {
|
||||||
return;
|
return;
|
||||||
@ -89,7 +97,10 @@ function MeasureTool({ map, active }: MapMeasureProps) {
|
|||||||
setIsBrushDown(true);
|
setIsBrushDown(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleBrushMove() {
|
function handleBrushMove(props: MapDragEvent) {
|
||||||
|
if (!leftMouseButton(props)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const brushPosition = getBrushPosition();
|
const brushPosition = getBrushPosition();
|
||||||
if (isBrushDown && drawingShapeData && brushPosition && mapImage) {
|
if (isBrushDown && drawingShapeData && brushPosition && mapImage) {
|
||||||
const { points } = getUpdatedShapeData(
|
const { points } = getUpdatedShapeData(
|
||||||
@ -123,7 +134,10 @@ function MeasureTool({ map, active }: MapMeasureProps) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleBrushUp() {
|
function handleBrushUp(props: MapDragEvent) {
|
||||||
|
if (!leftMouseButton(props)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
setDrawingShapeData(null);
|
setDrawingShapeData(null);
|
||||||
setIsBrushDown(false);
|
setIsBrushDown(false);
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,11 @@ import shortid from "shortid";
|
|||||||
import { Group } from "react-konva";
|
import { Group } from "react-konva";
|
||||||
import Konva from "konva";
|
import Konva from "konva";
|
||||||
|
|
||||||
import { useInteractionEmitter } from "../../contexts/MapInteractionContext";
|
import {
|
||||||
|
useInteractionEmitter,
|
||||||
|
MapDragEvent,
|
||||||
|
leftMouseButton,
|
||||||
|
} from "../../contexts/MapInteractionContext";
|
||||||
import { useMapStage } from "../../contexts/MapStageContext";
|
import { useMapStage } from "../../contexts/MapStageContext";
|
||||||
import { useUserId } from "../../contexts/UserIdContext";
|
import { useUserId } from "../../contexts/UserIdContext";
|
||||||
|
|
||||||
@ -72,7 +76,10 @@ function NoteTool({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleBrushDown() {
|
function handleBrushDown(props: MapDragEvent) {
|
||||||
|
if (!leftMouseButton(props)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const brushPosition = getBrushPosition();
|
const brushPosition = getBrushPosition();
|
||||||
if (!brushPosition || !userId) {
|
if (!brushPosition || !userId) {
|
||||||
return;
|
return;
|
||||||
@ -94,7 +101,10 @@ function NoteTool({
|
|||||||
setIsBrushDown(true);
|
setIsBrushDown(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleBrushMove() {
|
function handleBrushMove(props: MapDragEvent) {
|
||||||
|
if (!leftMouseButton(props)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (noteData) {
|
if (noteData) {
|
||||||
const brushPosition = getBrushPosition();
|
const brushPosition = getBrushPosition();
|
||||||
if (!brushPosition) {
|
if (!brushPosition) {
|
||||||
@ -114,7 +124,10 @@ function NoteTool({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleBrushUp() {
|
function handleBrushUp(props: MapDragEvent) {
|
||||||
|
if (!leftMouseButton(props)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (noteData && creatingNoteRef.current) {
|
if (noteData && creatingNoteRef.current) {
|
||||||
onNoteCreate([noteData]);
|
onNoteCreate([noteData]);
|
||||||
onNoteMenuOpen(noteData.id, creatingNoteRef.current, true);
|
onNoteMenuOpen(noteData.id, creatingNoteRef.current, true);
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
import { useEffect } from "react";
|
import { useEffect, useRef } from "react";
|
||||||
import { Group } from "react-konva";
|
import { Group } from "react-konva";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
useMapWidth,
|
useMapWidth,
|
||||||
useMapHeight,
|
useMapHeight,
|
||||||
useInteractionEmitter,
|
useInteractionEmitter,
|
||||||
|
MapDragEvent,
|
||||||
|
leftMouseButton,
|
||||||
|
rightMouseButton,
|
||||||
} from "../../contexts/MapInteractionContext";
|
} from "../../contexts/MapInteractionContext";
|
||||||
import { useMapStage } from "../../contexts/MapStageContext";
|
import { useMapStage } from "../../contexts/MapStageContext";
|
||||||
import { useGridStrokeWidth } from "../../contexts/GridContext";
|
import { useGridStrokeWidth } from "../../contexts/GridContext";
|
||||||
@ -41,11 +44,9 @@ function PointerTool({
|
|||||||
const gridStrokeWidth = useGridStrokeWidth();
|
const gridStrokeWidth = useGridStrokeWidth();
|
||||||
const mapStageRef = useMapStage();
|
const mapStageRef = useMapStage();
|
||||||
|
|
||||||
useEffect(() => {
|
const brushDownRef = useRef(false);
|
||||||
if (!active) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
const mapStage = mapStageRef.current;
|
const mapStage = mapStageRef.current;
|
||||||
|
|
||||||
function getBrushPosition() {
|
function getBrushPosition() {
|
||||||
@ -56,19 +57,27 @@ function PointerTool({
|
|||||||
return getRelativePointerPositionNormalized(mapImage);
|
return getRelativePointerPositionNormalized(mapImage);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleBrushDown() {
|
function handleBrushDown(props: MapDragEvent) {
|
||||||
|
if ((leftMouseButton(props) && active) || rightMouseButton(props)) {
|
||||||
const brushPosition = getBrushPosition();
|
const brushPosition = getBrushPosition();
|
||||||
brushPosition && onPointerDown?.(brushPosition);
|
brushPosition && onPointerDown?.(brushPosition);
|
||||||
|
brushDownRef.current = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleBrushMove() {
|
function handleBrushMove() {
|
||||||
|
if (brushDownRef.current) {
|
||||||
const brushPosition = getBrushPosition();
|
const brushPosition = getBrushPosition();
|
||||||
brushPosition && visible && onPointerMove?.(brushPosition);
|
brushPosition && visible && onPointerMove?.(brushPosition);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function handleBrushUp() {
|
function handleBrushUp() {
|
||||||
|
if (brushDownRef.current) {
|
||||||
const brushPosition = getBrushPosition();
|
const brushPosition = getBrushPosition();
|
||||||
brushPosition && onPointerUp?.(brushPosition);
|
brushPosition && onPointerUp?.(brushPosition);
|
||||||
|
brushDownRef.current = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interactionEmitter?.on("dragStart", handleBrushDown);
|
interactionEmitter?.on("dragStart", handleBrushDown);
|
||||||
|
@ -7,6 +7,8 @@ import {
|
|||||||
useMapWidth,
|
useMapWidth,
|
||||||
useMapHeight,
|
useMapHeight,
|
||||||
useInteractionEmitter,
|
useInteractionEmitter,
|
||||||
|
MapDragEvent,
|
||||||
|
leftMouseButton,
|
||||||
} from "../../contexts/MapInteractionContext";
|
} from "../../contexts/MapInteractionContext";
|
||||||
import { useMapStage } from "../../contexts/MapStageContext";
|
import { useMapStage } from "../../contexts/MapStageContext";
|
||||||
|
|
||||||
@ -96,7 +98,10 @@ function SelectTool({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleBrushDown() {
|
function handleBrushDown(props: MapDragEvent) {
|
||||||
|
if (!leftMouseButton(props)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const brushPosition = getBrushPosition();
|
const brushPosition = getBrushPosition();
|
||||||
if (!brushPosition || preventSelectionRef.current) {
|
if (!brushPosition || preventSelectionRef.current) {
|
||||||
return;
|
return;
|
||||||
@ -121,7 +126,10 @@ function SelectTool({
|
|||||||
setIsBrushDown(true);
|
setIsBrushDown(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleBrushMove() {
|
function handleBrushMove(props: MapDragEvent) {
|
||||||
|
if (!leftMouseButton(props)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const brushPosition = getBrushPosition();
|
const brushPosition = getBrushPosition();
|
||||||
if (!brushPosition || preventSelectionRef.current) {
|
if (!brushPosition || preventSelectionRef.current) {
|
||||||
return;
|
return;
|
||||||
@ -172,7 +180,10 @@ function SelectTool({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleBrushUp() {
|
function handleBrushUp(props: MapDragEvent) {
|
||||||
|
if (!leftMouseButton(props)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (preventSelectionRef.current) {
|
if (preventSelectionRef.current) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,21 @@
|
|||||||
import React, { useContext } from "react";
|
import React, { useContext } from "react";
|
||||||
import { EventEmitter } from "stream";
|
import { FullGestureState } from "react-use-gesture/dist/types";
|
||||||
import useDebounce from "../hooks/useDebounce";
|
import useDebounce from "../hooks/useDebounce";
|
||||||
|
import { TypedEmitter } from "tiny-typed-emitter";
|
||||||
|
|
||||||
|
export type MapDragEvent = Omit<FullGestureState<"drag">, "event"> & {
|
||||||
|
event: React.PointerEvent<Element> | PointerEvent;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type MapDragEventHandler = (props: MapDragEvent) => void;
|
||||||
|
|
||||||
|
export interface MapInteractionEvents {
|
||||||
|
dragStart: MapDragEventHandler;
|
||||||
|
drag: MapDragEventHandler;
|
||||||
|
dragEnd: MapDragEventHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class MapInteractionEmitter extends TypedEmitter<MapInteractionEvents> {}
|
||||||
|
|
||||||
type MapInteraction = {
|
type MapInteraction = {
|
||||||
stageScale: number;
|
stageScale: number;
|
||||||
@ -9,29 +24,33 @@ type MapInteraction = {
|
|||||||
setPreventMapInteraction: React.Dispatch<React.SetStateAction<boolean>>;
|
setPreventMapInteraction: React.Dispatch<React.SetStateAction<boolean>>;
|
||||||
mapWidth: number;
|
mapWidth: number;
|
||||||
mapHeight: number;
|
mapHeight: number;
|
||||||
interactionEmitter: EventEmitter | null;
|
interactionEmitter: MapInteractionEmitter | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const StageScaleContext =
|
export const StageScaleContext = React.createContext<
|
||||||
React.createContext<MapInteraction["stageScale"] | undefined>(undefined);
|
MapInteraction["stageScale"] | undefined
|
||||||
export const DebouncedStageScaleContext =
|
>(undefined);
|
||||||
React.createContext<MapInteraction["stageScale"] | undefined>(undefined);
|
export const DebouncedStageScaleContext = React.createContext<
|
||||||
export const StageWidthContext =
|
MapInteraction["stageScale"] | undefined
|
||||||
React.createContext<MapInteraction["stageWidth"] | undefined>(undefined);
|
>(undefined);
|
||||||
export const StageHeightContext =
|
export const StageWidthContext = React.createContext<
|
||||||
React.createContext<MapInteraction["stageHeight"] | undefined>(undefined);
|
MapInteraction["stageWidth"] | undefined
|
||||||
export const SetPreventMapInteractionContext =
|
>(undefined);
|
||||||
React.createContext<MapInteraction["setPreventMapInteraction"] | undefined>(
|
export const StageHeightContext = React.createContext<
|
||||||
undefined
|
MapInteraction["stageHeight"] | undefined
|
||||||
);
|
>(undefined);
|
||||||
export const MapWidthContext =
|
export const SetPreventMapInteractionContext = React.createContext<
|
||||||
React.createContext<MapInteraction["mapWidth"] | undefined>(undefined);
|
MapInteraction["setPreventMapInteraction"] | undefined
|
||||||
export const MapHeightContext =
|
>(undefined);
|
||||||
React.createContext<MapInteraction["mapHeight"] | undefined>(undefined);
|
export const MapWidthContext = React.createContext<
|
||||||
export const InteractionEmitterContext =
|
MapInteraction["mapWidth"] | undefined
|
||||||
React.createContext<MapInteraction["interactionEmitter"] | undefined>(
|
>(undefined);
|
||||||
undefined
|
export const MapHeightContext = React.createContext<
|
||||||
);
|
MapInteraction["mapHeight"] | undefined
|
||||||
|
>(undefined);
|
||||||
|
export const InteractionEmitterContext = React.createContext<
|
||||||
|
MapInteraction["interactionEmitter"] | undefined
|
||||||
|
>(undefined);
|
||||||
|
|
||||||
export function MapInteractionProvider({
|
export function MapInteractionProvider({
|
||||||
value,
|
value,
|
||||||
@ -152,3 +171,15 @@ export function useDebouncedStageScale() {
|
|||||||
}
|
}
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function leftMouseButton(event: MapDragEvent) {
|
||||||
|
return event.buttons <= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function middleMouseButton(event: MapDragEvent) {
|
||||||
|
return event.buttons === 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function rightMouseButton(event: MapDragEvent) {
|
||||||
|
return event.buttons === 2;
|
||||||
|
}
|
||||||
|
25
src/hooks/usePreventContextMenu.ts
Normal file
25
src/hooks/usePreventContextMenu.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import React, { useEffect } from "react";
|
||||||
|
|
||||||
|
function usePreventContextMenu(elementRef: React.RefObject<HTMLElement>) {
|
||||||
|
useEffect(() => {
|
||||||
|
// Stop conext menu i.e. right click dialog
|
||||||
|
function preventContextMenu(event: MouseEvent) {
|
||||||
|
event.preventDefault();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const element = elementRef.current;
|
||||||
|
if (element) {
|
||||||
|
element.addEventListener("contextmenu", preventContextMenu, {
|
||||||
|
passive: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
if (element) {
|
||||||
|
element.removeEventListener("contextmenu", preventContextMenu);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, [elementRef]);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default usePreventContextMenu;
|
@ -67,6 +67,7 @@ function useStageInteraction(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const { event, last } = props;
|
const { event, last } = props;
|
||||||
|
// Prevent double zoom on wheel end
|
||||||
if (!last) {
|
if (!last) {
|
||||||
const { pixelY } = normalizeWheel(event);
|
const { pixelY } = normalizeWheel(event);
|
||||||
|
|
||||||
@ -178,7 +179,7 @@ function useStageInteraction(
|
|||||||
gesture.onDragStart && gesture.onDragStart(props);
|
gesture.onDragStart && gesture.onDragStart(props);
|
||||||
},
|
},
|
||||||
onDrag: (props) => {
|
onDrag: (props) => {
|
||||||
const { delta, pinching } = props;
|
const { delta, pinching, buttons } = props;
|
||||||
const stage = stageRef.current;
|
const stage = stageRef.current;
|
||||||
if (
|
if (
|
||||||
preventInteraction ||
|
preventInteraction ||
|
||||||
@ -191,7 +192,8 @@ function useStageInteraction(
|
|||||||
|
|
||||||
const [dx, dy] = delta;
|
const [dx, dy] = delta;
|
||||||
const stageTranslate = stageTranslateRef.current;
|
const stageTranslate = stageTranslateRef.current;
|
||||||
if (tool === "move") {
|
// Move with move tool and left click or any mouse button but right click
|
||||||
|
if ((tool === "move" && buttons < 2) || buttons > 2) {
|
||||||
const newTranslate = {
|
const newTranslate = {
|
||||||
x: stageTranslate.x + dx,
|
x: stageTranslate.x + dx,
|
||||||
y: stageTranslate.y + dy,
|
y: stageTranslate.y + dy,
|
||||||
|
@ -13181,6 +13181,11 @@ tiny-invariant@^1.0.2:
|
|||||||
resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.1.0.tgz#634c5f8efdc27714b7f386c35e6760991d230875"
|
resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.1.0.tgz#634c5f8efdc27714b7f386c35e6760991d230875"
|
||||||
integrity sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw==
|
integrity sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw==
|
||||||
|
|
||||||
|
tiny-typed-emitter@^2.1.0:
|
||||||
|
version "2.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/tiny-typed-emitter/-/tiny-typed-emitter-2.1.0.tgz#b3b027fdd389ff81a152c8e847ee2f5be9fad7b5"
|
||||||
|
integrity sha512-qVtvMxeXbVej0cQWKqVSSAHmKZEHAvxdF8HEUBFWts8h+xEo5m/lEiPakuyZ3BnCBjOD8i24kzNOiOLLgsSxhA==
|
||||||
|
|
||||||
tiny-warning@^1.0.0, tiny-warning@^1.0.3:
|
tiny-warning@^1.0.0, tiny-warning@^1.0.3:
|
||||||
version "1.0.3"
|
version "1.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754"
|
resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754"
|
||||||
|
Loading…
Reference in New Issue
Block a user