From 0bec5821164fe02806cb44c2d126c2fee1ab4d3f Mon Sep 17 00:00:00 2001 From: Mitchell McCaffrey Date: Sun, 21 Jun 2020 16:29:42 +1000 Subject: [PATCH] Moved drawing to use native konva events --- src/components/map/MapDrawing.js | 170 +++++++++++++++---------------- src/helpers/useMapBrush.js | 71 ------------- 2 files changed, 85 insertions(+), 156 deletions(-) delete mode 100644 src/helpers/useMapBrush.js diff --git a/src/components/map/MapDrawing.js b/src/components/map/MapDrawing.js index 9fb49b8..e83cac7 100644 --- a/src/components/map/MapDrawing.js +++ b/src/components/map/MapDrawing.js @@ -1,8 +1,9 @@ -import React, { useContext, useState, useCallback } from "react"; +import React, { useContext, useState, useEffect } from "react"; import shortid from "shortid"; import { Group, Line, Rect, Circle } from "react-konva"; import MapInteractionContext from "../../contexts/MapInteractionContext"; +import MapStageContext from "../../contexts/MapStageContext"; import { compare as comparePoints } from "../../helpers/vector2"; import { @@ -12,9 +13,9 @@ import { simplifyPoints, getStrokeWidth, } from "../../helpers/drawing"; +import { getRelativePointerPositionNormalized } from "../../helpers/konva"; import colors from "../../helpers/colors"; -import useMapBrush from "../../helpers/useMapBrush"; function MapDrawing({ shapes, @@ -25,6 +26,7 @@ function MapDrawing({ gridSize, }) { const { stageScale, mapWidth, mapHeight } = useContext(MapInteractionContext); + const mapStageRef = useContext(MapStageContext); const [drawingShape, setDrawingShape] = useState(null); const [isBrushDown, setIsBrushDown] = useState(false); const [erasingShapes, setErasingShapes] = useState([]); @@ -42,57 +44,53 @@ function MapDrawing({ selectedToolSettings.type === "circle" || selectedToolSettings.type === "triangle"); - const handleBrushUp = useCallback(() => { - setIsBrushDown(false); - if (erasingShapes.length > 0) { - onShapesRemove(erasingShapes.map((shape) => shape.id)); - setErasingShapes([]); + useEffect(() => { + if (!isEditing) { + return; } - }, [erasingShapes, onShapesRemove]); + const mapStage = mapStageRef.current; - 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 (isBrush) { - setDrawingShape({ - type: "path", - pathType: selectedToolSettings.type === "brush" ? "stroke" : "fill", - data: { points: [brushPosition] }, - strokeWidth: selectedToolSettings.type === "brush" ? 1 : 0, - ...commonShapeData, - }); - } else if (isShape) { - setDrawingShape({ - type: "shape", - shapeType: selectedToolSettings.type, - data: getDefaultShapeData(selectedToolSettings.type, brushPosition), - strokeWidth: 0, - ...commonShapeData, - }); - } - setIsBrushDown(true); + function getBrushPosition() { + const mapImage = mapStage.findOne("#mapImage"); + return getBrushPositionForTool( + getRelativePointerPositionNormalized(mapImage), + selectedToolId, + selectedToolSettings, + gridSize, + shapes + ); + } + + function handleBrushDown() { + const brushPosition = getBrushPosition(); + const commonShapeData = { + color: selectedToolSettings && selectedToolSettings.color, + blend: selectedToolSettings && selectedToolSettings.useBlending, + id: shortid.generate(), + }; + if (isBrush) { + setDrawingShape({ + type: "path", + pathType: selectedToolSettings.type === "brush" ? "stroke" : "fill", + data: { points: [brushPosition] }, + strokeWidth: selectedToolSettings.type === "brush" ? 1 : 0, + ...commonShapeData, + }); + } else if (isShape) { + setDrawingShape({ + type: "shape", + shapeType: selectedToolSettings.type, + data: getDefaultShapeData(selectedToolSettings.type, brushPosition), + strokeWidth: 0, + ...commonShapeData, + }); } + setIsBrushDown(true); + } - function continueShape() { - const brushPosition = getBrushPositionForTool( - mapBrushPosition, - selectedToolId, - selectedToolSettings, - gridSize, - shapes - ); + function handleBrushMove() { + const brushPosition = getBrushPosition(); + if (isBrushDown && drawingShape) { if (isBrush) { setDrawingShape((prevShape) => { const prevPoints = prevShape.data.points; @@ -127,49 +125,51 @@ function MapDrawing({ })); } } + } - function endShape() { - if (isBrush && drawingShape) { - if (drawingShape.data.points.length > 1) { - onShapeAdd(drawingShape); - } - } else if (isShape && drawingShape) { + function handleBrushUp() { + if (isBrush && drawingShape) { + if (drawingShape.data.points.length > 1) { onShapeAdd(drawingShape); } - setDrawingShape(null); - handleBrushUp(); + } else if (isShape && drawingShape) { + onShapeAdd(drawingShape); } - switch (brushState) { - case "first": - startShape(); - return; - case "drawing": - continueShape(); - return; - case "last": - endShape(); - return; - default: - return; + if (erasingShapes.length > 0) { + onShapesRemove(erasingShapes.map((shape) => shape.id)); + setErasingShapes([]); } - }, - [ - selectedToolId, - selectedToolSettings, - gridSize, - stageScale, - onShapeAdd, - shapes, - drawingShape, - handleBrushUp, - isBrush, - isShape, - ] - ); - // Move away from this as it is too slow to respond - useMapBrush(isEditing, handleShapeDraw); + setDrawingShape(null); + setIsBrushDown(false); + } + + mapStage.on("mousedown touchstart", handleBrushDown); + mapStage.on("mousemove touchmove", handleBrushMove); + mapStage.on("mouseup touchend", handleBrushUp); + + return () => { + mapStage.off("mousedown touchstart", handleBrushDown); + mapStage.off("mousemove touchmove", handleBrushMove); + mapStage.off("mouseup touchend", handleBrushUp); + }; + }, [ + drawingShape, + erasingShapes, + gridSize, + isBrush, + isBrushDown, + isEditing, + isShape, + mapStageRef, + onShapeAdd, + onShapesRemove, + selectedToolId, + selectedToolSettings, + shapes, + stageScale, + ]); function handleShapeOver(shape, isDown) { if (shouldHover && isDown) { diff --git a/src/helpers/useMapBrush.js b/src/helpers/useMapBrush.js deleted file mode 100644 index 3c96f7d..0000000 --- a/src/helpers/useMapBrush.js +++ /dev/null @@ -1,71 +0,0 @@ -import { useContext, useRef, useEffect } from "react"; - -import MapInteractionContext from "../contexts/MapInteractionContext"; - -import { compare } from "./vector2"; - -import usePrevious from "./usePrevious"; - -/** - * @callback onBrushUpdate - * @param {string} drawState "first" | "drawing" | "last" - * @param {Object} brushPosition the normalized x and y coordinates of the brush on the map - */ - -/** - * Helper to get the maps drag position as it changes - * @param {boolean} shouldUpdate - * @param {onBrushUpdate} onBrushUpdate - */ -function useMapBrush(shouldUpdate, onBrushUpdate) { - const { stageDragState, mapDragPositionRef } = useContext( - MapInteractionContext - ); - - const requestRef = useRef(); - const previousDragState = usePrevious(stageDragState); - const previousBrushPositionRef = useRef(mapDragPositionRef.current); - - useEffect(() => { - function updateBrush(forceUpdate) { - const drawState = - stageDragState === "dragging" ? "drawing" : stageDragState; - const brushPosition = mapDragPositionRef.current; - const previousBrushPostition = previousBrushPositionRef.current; - // Only update brush when it has moved - if ( - !compare(brushPosition, previousBrushPostition, 0.0001) || - forceUpdate - ) { - onBrushUpdate(drawState, brushPosition); - previousBrushPositionRef.current = brushPosition; - } - } - - function animate() { - if (!shouldUpdate) { - return; - } - requestRef.current = requestAnimationFrame(animate); - updateBrush(false); - } - - requestRef.current = requestAnimationFrame(animate); - - if (stageDragState !== previousDragState && shouldUpdate) { - updateBrush(true); - } - - return () => { - cancelAnimationFrame(requestRef.current); - }; - }, [ - shouldUpdate, - onBrushUpdate, - stageDragState, - mapDragPositionRef, - previousDragState, - ]); -} - -export default useMapBrush;