diff --git a/src/components/map/MapToken.js b/src/components/map/MapToken.js
index d9dff3f..f6fd65d 100644
--- a/src/components/map/MapToken.js
+++ b/src/components/map/MapToken.js
@@ -6,7 +6,7 @@ import useImage from "use-image";
import useDataSource from "../../helpers/useDataSource";
import useDebounce from "../../helpers/useDebounce";
import usePrevious from "../../helpers/usePrevious";
-import * as Vector2 from "../../helpers/vector2";
+import { snapNodeToMap } from "../../helpers/map";
import AuthContext from "../../contexts/AuthContext";
import MapInteractionContext from "../../contexts/MapInteractionContext";
@@ -82,35 +82,7 @@ function MapToken({
const tokenGroup = event.target;
// Snap to corners of grid
if (map.snapToGrid) {
- const offset = Vector2.multiply(map.grid.inset.topLeft, {
- x: mapWidth,
- y: mapHeight,
- });
- const position = {
- x: tokenGroup.x() + tokenGroup.width() / 2,
- y: tokenGroup.y() + tokenGroup.height() / 2,
- };
- const gridSize = {
- x:
- (mapWidth *
- (map.grid.inset.bottomRight.x - map.grid.inset.topLeft.x)) /
- map.grid.size.x,
- y:
- (mapHeight *
- (map.grid.inset.bottomRight.y - map.grid.inset.topLeft.y)) /
- map.grid.size.y,
- };
- // Transform into offset space, round, then transform back
- const gridSnap = Vector2.add(
- Vector2.roundTo(Vector2.subtract(position, offset), gridSize),
- offset
- );
- const gridDistance = Vector2.length(Vector2.subtract(gridSnap, position));
- const minGrid = Vector2.min(gridSize);
- if (gridDistance < minGrid * snappingThreshold) {
- tokenGroup.x(gridSnap.x - tokenGroup.width() / 2);
- tokenGroup.y(gridSnap.y - tokenGroup.height() / 2);
- }
+ snapNodeToMap(map, mapWidth, mapHeight, tokenGroup, snappingThreshold);
}
}
diff --git a/src/components/note/Note.js b/src/components/note/Note.js
index 51f9c1c..d11da63 100644
--- a/src/components/note/Note.js
+++ b/src/components/note/Note.js
@@ -5,7 +5,7 @@ import { useSpring, animated } from "react-spring/konva";
import AuthContext from "../../contexts/AuthContext";
import MapInteractionContext from "../../contexts/MapInteractionContext";
-import * as Vector2 from "../../helpers/vector2";
+import { snapNodeToMap } from "../../helpers/map";
import colors from "../../helpers/colors";
import usePrevious from "../../helpers/usePrevious";
@@ -37,35 +37,7 @@ function Note({
const noteGroup = event.target;
// Snap to corners of grid
if (map.snapToGrid) {
- const offset = Vector2.multiply(map.grid.inset.topLeft, {
- x: mapWidth,
- y: mapHeight,
- });
- const position = {
- x: noteGroup.x() + noteGroup.width() / 2,
- y: noteGroup.y() + noteGroup.height() / 2,
- };
- const gridSize = {
- x:
- (mapWidth *
- (map.grid.inset.bottomRight.x - map.grid.inset.topLeft.x)) /
- map.grid.size.x,
- y:
- (mapHeight *
- (map.grid.inset.bottomRight.y - map.grid.inset.topLeft.y)) /
- map.grid.size.y,
- };
- // Transform into offset space, round, then transform back
- const gridSnap = Vector2.add(
- Vector2.roundTo(Vector2.subtract(position, offset), gridSize),
- offset
- );
- const gridDistance = Vector2.length(Vector2.subtract(gridSnap, position));
- const minGrid = Vector2.min(gridSize);
- if (gridDistance < minGrid * snappingThreshold) {
- noteGroup.x(gridSnap.x - noteGroup.width() / 2);
- noteGroup.y(gridSnap.y - noteGroup.height() / 2);
- }
+ snapNodeToMap(map, mapWidth, mapHeight, noteGroup, snappingThreshold);
}
}
diff --git a/src/components/note/NoteMenu.js b/src/components/note/NoteMenu.js
index 0fd0732..6ea59cb 100644
--- a/src/components/note/NoteMenu.js
+++ b/src/components/note/NoteMenu.js
@@ -63,7 +63,7 @@ function NoteMenu({
}
function handleSizeChange(event) {
- const newSize = parseInt(event.target.value);
+ const newSize = parseFloat(event.target.value);
note && onNoteChange({ ...note, size: newSize });
}
@@ -177,8 +177,8 @@ function NoteMenu({
diff --git a/src/components/token/TokenMenu.js b/src/components/token/TokenMenu.js
index 2009a17..645cbe2 100644
--- a/src/components/token/TokenMenu.js
+++ b/src/components/token/TokenMenu.js
@@ -72,7 +72,7 @@ function TokenMenu({
}
function handleSizeChange(event) {
- const newSize = parseInt(event.target.value);
+ const newSize = parseFloat(event.target.value);
tokenState &&
onTokenStateChange({ [tokenState.id]: { ...tokenState, size: newSize } });
}
@@ -211,8 +211,8 @@ function TokenMenu({
diff --git a/src/helpers/map.js b/src/helpers/map.js
index 3ded592..a2101dc 100644
--- a/src/helpers/map.js
+++ b/src/helpers/map.js
@@ -1,4 +1,5 @@
import GridSizeModel from "../ml/gridSize/GridSizeModel";
+import * as Vector2 from "./vector2";
import { logError } from "./logging";
@@ -162,3 +163,64 @@ export function getMapMaxZoom(map) {
// Return max grid size / 2
return Math.max(Math.min(map.grid.size.x, map.grid.size.y) / 2, 5);
}
+
+export function snapNodeToMap(
+ map,
+ mapWidth,
+ mapHeight,
+ node,
+ snappingThreshold
+) {
+ const offset = Vector2.multiply(map.grid.inset.topLeft, {
+ x: mapWidth,
+ y: mapHeight,
+ });
+ const gridSize = {
+ x:
+ (mapWidth * (map.grid.inset.bottomRight.x - map.grid.inset.topLeft.x)) /
+ map.grid.size.x,
+ y:
+ (mapHeight * (map.grid.inset.bottomRight.y - map.grid.inset.topLeft.y)) /
+ map.grid.size.y,
+ };
+
+ const position = node.position();
+ const halfSize = Vector2.divide({ x: node.width(), y: node.height() }, 2);
+
+ // Offsets to tranform the centered position into the four corners
+ const cornerOffsets = [
+ halfSize,
+ { x: -halfSize.x, y: -halfSize.y },
+ { x: halfSize.x, y: -halfSize.y },
+ { x: -halfSize.x, y: halfSize.y },
+ ];
+
+ // Minimum distance from a corner to the grid
+ let minCornerGridDistance = Number.MAX_VALUE;
+ // Minimum component of the difference between the min corner and the grid
+ let minCornerMinComponent;
+ // Closest grid value
+ let minGridSnap;
+
+ // Find the closest corner to the grid
+ for (let cornerOffset of cornerOffsets) {
+ const corner = Vector2.add(position, cornerOffset);
+ // Transform into offset space, round, then transform back
+ const gridSnap = Vector2.add(
+ Vector2.roundTo(Vector2.subtract(corner, offset), gridSize),
+ offset
+ );
+ const gridDistance = Vector2.length(Vector2.subtract(gridSnap, corner));
+ const minComponent = Vector2.min(gridSize);
+ if (gridDistance < minCornerGridDistance) {
+ minCornerGridDistance = gridDistance;
+ minCornerMinComponent = minComponent;
+ // Move the grid value back to the center
+ minGridSnap = Vector2.subtract(gridSnap, cornerOffset);
+ }
+ }
+
+ if (minCornerGridDistance < minCornerMinComponent * snappingThreshold) {
+ node.position(minGridSnap);
+ }
+}