From de84e77e589d0b31916841b13142c3895ac0eb7c Mon Sep 17 00:00:00 2001 From: Mitchell McCaffrey Date: Thu, 4 Feb 2021 15:06:34 +1100 Subject: [PATCH] Add basic hex functionality and clean up hooks and Vector2 class --- src/components/Grid.js | 148 ++- src/components/dice/DiceButtons.js | 2 +- src/components/dice/DiceInteraction.js | 2 +- src/components/dice/DiceTrayOverlay.js | 2 +- src/components/map/MapControls.js | 2 +- src/components/map/MapDrawing.js | 4 +- src/components/map/MapEditor.js | 15 +- src/components/map/MapFog.js | 9 +- src/components/map/MapGrid.js | 11 +- src/components/map/MapGridEditor.js | 5 +- src/components/map/MapInteraction.js | 15 +- src/components/map/MapMeasure.js | 2 +- src/components/map/MapPointer.js | 4 +- src/components/map/MapSettings.js | 20 +- src/components/map/MapTile.js | 2 +- src/components/map/MapTiles.js | 2 +- src/components/map/MapToken.js | 17 +- .../map/controls/DrawingToolSettings.js | 2 +- .../map/controls/FogToolSettings.js | 2 +- .../map/controls/MeasureToolSettings.js | 2 +- src/components/note/Note.js | 13 +- src/components/note/NoteMenu.js | 2 +- src/components/party/DiceTrayButton.js | 2 +- src/components/party/Party.js | 2 +- src/components/party/Timer.js | 2 +- src/components/token/ListToken.js | 4 +- src/components/token/ProxyToken.js | 2 +- src/components/token/TokenLabel.js | 2 +- src/components/token/TokenMenu.js | 2 +- src/components/token/TokenPreview.js | 20 +- src/components/token/TokenTile.js | 2 +- src/components/token/TokenTiles.js | 2 +- src/components/token/Tokens.js | 3 +- src/contexts/PlayerContext.js | 3 +- src/database.js | 2 +- src/helpers/drawing.js | 2 +- src/helpers/{map.js => grid.js} | 172 +++- src/helpers/konva.js | 2 +- src/helpers/vector2.js | 843 +++++++++--------- src/{helpers => hooks}/useDataSource.js | 0 src/{helpers => hooks}/useDebounce.js | 0 src/{helpers => hooks}/useImageCenter.js | 0 src/{helpers => hooks}/useKeyboard.js | 0 src/{helpers => hooks}/useMapImage.js | 0 src/{helpers => hooks}/useNetworkedState.js | 2 +- src/{helpers => hooks}/usePortal.js | 0 .../usePreventOverscroll.js | 0 src/{helpers => hooks}/usePreventTouch.js | 0 src/{helpers => hooks}/usePrevious.js | 0 src/{helpers => hooks}/useResponsiveLayout.js | 0 src/{helpers => hooks}/useSetting.js | 0 src/{helpers => hooks}/useStageInteraction.js | 0 src/modals/EditMapModal.js | 5 +- src/modals/EditTokenModal.js | 3 +- src/modals/SelectMapModal.js | 14 +- src/modals/SelectTokensModal.js | 5 +- src/modals/SettingsModal.js | 2 +- src/modals/StartModal.js | 2 +- src/modals/StartTimerModal.js | 2 +- src/network/NetworkedMapAndTokens.js | 6 +- src/network/NetworkedMapPointer.js | 17 +- 61 files changed, 835 insertions(+), 573 deletions(-) rename src/helpers/{map.js => grid.js} (57%) rename src/{helpers => hooks}/useDataSource.js (100%) rename src/{helpers => hooks}/useDebounce.js (100%) rename src/{helpers => hooks}/useImageCenter.js (100%) rename src/{helpers => hooks}/useKeyboard.js (100%) rename src/{helpers => hooks}/useMapImage.js (100%) rename src/{helpers => hooks}/useNetworkedState.js (98%) rename src/{helpers => hooks}/usePortal.js (100%) rename src/{helpers => hooks}/usePreventOverscroll.js (100%) rename src/{helpers => hooks}/usePreventTouch.js (100%) rename src/{helpers => hooks}/usePrevious.js (100%) rename src/{helpers => hooks}/useResponsiveLayout.js (100%) rename src/{helpers => hooks}/useSetting.js (100%) rename src/{helpers => hooks}/useStageInteraction.js (100%) diff --git a/src/components/Grid.js b/src/components/Grid.js index e50de78..40a5b91 100644 --- a/src/components/Grid.js +++ b/src/components/Grid.js @@ -1,71 +1,121 @@ import React from "react"; -import { Line, Group } from "react-konva"; +import { Line, Group, RegularPolygon } from "react-konva"; import { getStrokeWidth } from "../helpers/drawing"; +import { getCellSize, getCellLocation, shouldClampCell } from "../helpers/grid"; -function Grid({ gridX, gridY, gridInset, strokeWidth, width, height, stroke }) { - if (!gridX || !gridY) { +function Grid({ grid, strokeWidth, width, height, stroke }) { + if (!grid?.size.x || !grid?.size.y) { return null; } const gridSizeNormalized = { - x: (gridInset.bottomRight.x - gridInset.topLeft.x) / gridX, - y: (gridInset.bottomRight.y - gridInset.topLeft.y) / gridY, + x: (grid.inset.bottomRight.x - grid.inset.topLeft.x) / grid.size.x, + y: (grid.inset.bottomRight.y - grid.inset.topLeft.y) / grid.size.y, }; - const insetWidth = (gridInset.bottomRight.x - gridInset.topLeft.x) * width; - const insetHeight = (gridInset.bottomRight.y - gridInset.topLeft.y) * height; + const insetWidth = (grid.inset.bottomRight.x - grid.inset.topLeft.x) * width; + const insetHeight = + (grid.inset.bottomRight.y - grid.inset.topLeft.y) * height; - const lineSpacingX = insetWidth / gridX; - const lineSpacingY = insetHeight / gridY; + const offsetX = grid.inset.topLeft.x * width * -1; + const offsetY = grid.inset.topLeft.y * height * -1; - const offsetX = gridInset.topLeft.x * width * -1; - const offsetY = gridInset.topLeft.y * height * -1; + const cellSize = getCellSize(grid, insetWidth, insetHeight); - const lines = []; - for (let x = 1; x < gridX; x++) { - lines.push( - - ); - } - for (let y = 1; y < gridY; y++) { - lines.push( - - ); + const shapes = []; + if (grid.type === "square") { + for (let x = 1; x < grid.size.x; x++) { + shapes.push( + + ); + } + for (let y = 1; y < grid.size.y; y++) { + shapes.push( + + ); + } + } else if (grid.type === "hexVertical" || grid.type === "hexHorizontal") { + for (let x = 0; x < grid.size.x; x++) { + for (let y = 0; y < grid.size.y; y++) { + const cellLocation = getCellLocation(grid, x, y, cellSize); + + // If our hex shape will go past the bounds of the grid + const overshot = shouldClampCell(grid, x, y); + shapes.push( + { + context.rect( + -cellSize.radius, + -cellSize.radius, + grid.type === "hexVertical" + ? cellSize.radius + : cellSize.radius * 2, + grid.type === "hexVertical" + ? cellSize.radius * 2 + : cellSize.radius + ); + }) + } + x={cellLocation.x} + y={cellLocation.y} + offsetX={offsetX} + offsetY={offsetY} + > + + + ); + } + } } - return {lines}; + return {shapes}; } Grid.defaultProps = { strokeWidth: 0.1, - gridInset: { topLeft: { x: 0, y: 0 }, bottomRight: { x: 1, y: 1 } }, stroke: "white", }; diff --git a/src/components/dice/DiceButtons.js b/src/components/dice/DiceButtons.js index b44ffd1..f966113 100644 --- a/src/components/dice/DiceButtons.js +++ b/src/components/dice/DiceButtons.js @@ -19,7 +19,7 @@ import SelectDiceButton from "./SelectDiceButton"; import Divider from "../Divider"; import { dice } from "../../dice"; -import useSetting from "../../helpers/useSetting"; +import useSetting from "../../hooks/useSetting"; function DiceButtons({ diceRolls, diff --git a/src/components/dice/DiceInteraction.js b/src/components/dice/DiceInteraction.js index 24bff59..f2aa842 100644 --- a/src/components/dice/DiceInteraction.js +++ b/src/components/dice/DiceInteraction.js @@ -16,7 +16,7 @@ import "@babylonjs/loaders/glTF"; import ReactResizeDetector from "react-resize-detector"; -import usePreventTouch from "../../helpers/usePreventTouch"; +import usePreventTouch from "../../hooks/usePreventTouch"; const diceThrowSpeed = 2; diff --git a/src/components/dice/DiceTrayOverlay.js b/src/components/dice/DiceTrayOverlay.js index e0ee084..ce78dce 100644 --- a/src/components/dice/DiceTrayOverlay.js +++ b/src/components/dice/DiceTrayOverlay.js @@ -24,7 +24,7 @@ import DiceTray from "../../dice/diceTray/DiceTray"; import DiceLoadingContext from "../../contexts/DiceLoadingContext"; import { getDiceRoll } from "../../helpers/dice"; -import useSetting from "../../helpers/useSetting"; +import useSetting from "../../hooks/useSetting"; function DiceTrayOverlay({ isOpen, diff --git a/src/components/map/MapControls.js b/src/components/map/MapControls.js index 9cc968b..fb13f6e 100644 --- a/src/components/map/MapControls.js +++ b/src/components/map/MapControls.js @@ -21,7 +21,7 @@ import FullScreenIcon from "../../icons/FullScreenIcon"; import FullScreenExitIcon from "../../icons/FullScreenExitIcon"; import NoteToolIcon from "../../icons/NoteToolIcon"; -import useSetting from "../../helpers/useSetting"; +import useSetting from "../../hooks/useSetting"; function MapContols({ onMapChange, diff --git a/src/components/map/MapDrawing.js b/src/components/map/MapDrawing.js index eadd4b5..a460aeb 100644 --- a/src/components/map/MapDrawing.js +++ b/src/components/map/MapDrawing.js @@ -5,7 +5,7 @@ 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 Vector2 from "../../helpers/Vector2"; import { getBrushPosition, getDefaultShapeData, @@ -92,7 +92,7 @@ function MapDrawing({ setDrawingShape((prevShape) => { const prevPoints = prevShape.data.points; if ( - comparePoints( + Vector2.compare( prevPoints[prevPoints.length - 1], brushPosition, 0.001 diff --git a/src/components/map/MapEditor.js b/src/components/map/MapEditor.js index d6b22d2..b4d7a06 100644 --- a/src/components/map/MapEditor.js +++ b/src/components/map/MapEditor.js @@ -3,12 +3,13 @@ import { Box, IconButton } from "theme-ui"; import { Stage, Layer, Image } from "react-konva"; import ReactResizeDetector from "react-resize-detector"; -import useMapImage from "../../helpers/useMapImage"; -import usePreventOverscroll from "../../helpers/usePreventOverscroll"; -import useStageInteraction from "../../helpers/useStageInteraction"; -import useImageCenter from "../../helpers/useImageCenter"; -import { getMapDefaultInset, getMapMaxZoom } from "../../helpers/map"; -import useResponsiveLayout from "../../helpers/useResponsiveLayout"; +import useMapImage from "../../hooks/useMapImage"; +import usePreventOverscroll from "../../hooks/usePreventOverscroll"; +import useStageInteraction from "../../hooks/useStageInteraction"; +import useImageCenter from "../../hooks/useImageCenter"; +import useResponsiveLayout from "../../hooks/useResponsiveLayout"; + +import { getMapDefaultInset, getGridMaxZoom } from "../../helpers/grid"; import { MapInteractionProvider } from "../../contexts/MapInteractionContext"; import KeyboardContext from "../../contexts/KeyboardContext"; @@ -65,7 +66,7 @@ function MapEditor({ map, onSettingsChange }) { setStageScale, stageTranslateRef, mapLayerRef.current, - getMapMaxZoom(map), + getGridMaxZoom(map.grid), "pan", preventMapInteraction ); diff --git a/src/components/map/MapFog.js b/src/components/map/MapFog.js index d9e78a8..ae7209b 100644 --- a/src/components/map/MapFog.js +++ b/src/components/map/MapFog.js @@ -14,7 +14,7 @@ import diagonalPattern from "../../images/DiagonalPattern.png"; import MapInteractionContext from "../../contexts/MapInteractionContext"; import MapStageContext from "../../contexts/MapStageContext"; -import { compare as comparePoints } from "../../helpers/vector2"; +import Vector2 from "../../helpers/Vector2"; import { getFogBrushPosition, simplifyPoints, @@ -23,8 +23,9 @@ import { } from "../../helpers/drawing"; import colors from "../../helpers/colors"; import { HoleyLine, Tick } from "../../helpers/konva"; -import useKeyboard from "../../helpers/useKeyboard"; -import useDebounce from "../../helpers/useDebounce"; + +import useKeyboard from "../../hooks/useKeyboard"; +import useDebounce from "../../hooks/useDebounce"; function MapFog({ map, @@ -120,7 +121,7 @@ function MapFog({ setDrawingShape((prevShape) => { const prevPoints = prevShape.data.points; if ( - comparePoints( + Vector2.compare( prevPoints[prevPoints.length - 1], brushPosition, 0.001 diff --git a/src/components/map/MapGrid.js b/src/components/map/MapGrid.js index 589d0e4..4e7a2b1 100644 --- a/src/components/map/MapGrid.js +++ b/src/components/map/MapGrid.js @@ -3,7 +3,7 @@ import useImage from "use-image"; import MapInteractionContext from "../../contexts/MapInteractionContext"; -import useDataSource from "../../helpers/useDataSource"; +import useDataSource from "../../hooks/useDataSource"; import { mapSources as defaultMapSources } from "../../maps"; import { getImageLightness } from "../../helpers/image"; @@ -33,16 +33,9 @@ function MapGrid({ map, strokeWidth }) { } }, [mapImage, mapLoadingStatus]); - const gridX = map && map.grid.size.x; - const gridY = map && map.grid.size.y; - - const gridInset = map && map.grid.inset; - return ( {visible && (