Added simple pointer tool
This commit is contained in:
parent
9efc84434b
commit
c6f9b29cc3
@ -10,6 +10,7 @@ import MapDice from "./MapDice";
|
||||
import MapGrid from "./MapGrid";
|
||||
import MapMeasure from "./MapMeasure";
|
||||
import MapLoadingOverlay from "./MapLoadingOverlay";
|
||||
import NetworkedMapPointer from "../../network/NetworkedMapPointer";
|
||||
|
||||
import TokenDataContext from "../../contexts/TokenDataContext";
|
||||
|
||||
@ -35,6 +36,7 @@ function Map({
|
||||
allowFogDrawing,
|
||||
allowMapChange,
|
||||
disabledTokens,
|
||||
session,
|
||||
}) {
|
||||
const { tokensById } = useContext(TokenDataContext);
|
||||
|
||||
@ -139,6 +141,7 @@ function Map({
|
||||
if (!map) {
|
||||
disabledControls.push("pan");
|
||||
disabledControls.push("measure");
|
||||
disabledControls.push("pointer");
|
||||
}
|
||||
if (!allowFogDrawing) {
|
||||
disabledControls.push("fog");
|
||||
@ -304,6 +307,14 @@ function Map({
|
||||
/>
|
||||
);
|
||||
|
||||
const mapPointer = (
|
||||
<NetworkedMapPointer
|
||||
active={selectedToolId === "pointer"}
|
||||
gridSize={gridSizeNormalized}
|
||||
session={session}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<MapInteraction
|
||||
map={map}
|
||||
@ -324,6 +335,7 @@ function Map({
|
||||
{mapDrawing}
|
||||
{mapTokens}
|
||||
{mapFog}
|
||||
{mapPointer}
|
||||
{mapMeasure}
|
||||
</MapInteraction>
|
||||
);
|
||||
|
@ -15,6 +15,7 @@ import FogToolIcon from "../../icons/FogToolIcon";
|
||||
import BrushToolIcon from "../../icons/BrushToolIcon";
|
||||
import MeasureToolIcon from "../../icons/MeasureToolIcon";
|
||||
import ExpandMoreIcon from "../../icons/ExpandMoreIcon";
|
||||
import PointerToolIcon from "../../icons/PointerToolIcon";
|
||||
|
||||
function MapContols({
|
||||
onMapChange,
|
||||
@ -55,8 +56,13 @@ function MapContols({
|
||||
title: "Measure Tool",
|
||||
SettingsComponent: MeasureToolSettings,
|
||||
},
|
||||
pointer: {
|
||||
id: "pointer",
|
||||
icon: <PointerToolIcon />,
|
||||
title: "Pointer Tool",
|
||||
},
|
||||
};
|
||||
const tools = ["pan", "fog", "drawing", "measure"];
|
||||
const tools = ["pan", "fog", "drawing", "measure", "pointer"];
|
||||
|
||||
const sections = [
|
||||
{
|
||||
|
81
src/components/map/MapPointer.js
Normal file
81
src/components/map/MapPointer.js
Normal file
@ -0,0 +1,81 @@
|
||||
import React, { useContext, useEffect } from "react";
|
||||
import { Group, Circle } from "react-konva";
|
||||
|
||||
import MapInteractionContext from "../../contexts/MapInteractionContext";
|
||||
import MapStageContext from "../../contexts/MapStageContext";
|
||||
|
||||
import { getStrokeWidth } from "../../helpers/drawing";
|
||||
import { getRelativePointerPositionNormalized } from "../../helpers/konva";
|
||||
|
||||
import colors from "../../helpers/colors";
|
||||
|
||||
function MapPointer({
|
||||
gridSize,
|
||||
active,
|
||||
position,
|
||||
onPointerDown,
|
||||
onPointerMove,
|
||||
onPointerUp,
|
||||
visible,
|
||||
}) {
|
||||
const { mapWidth, mapHeight, interactionEmitter } = useContext(
|
||||
MapInteractionContext
|
||||
);
|
||||
const mapStageRef = useContext(MapStageContext);
|
||||
|
||||
// const [isBrushDown, setIsBrushDown] = useState(false);
|
||||
// const [brushPosition, setBrushPosition] = useState({ x: 0, y: 0 });
|
||||
|
||||
useEffect(() => {
|
||||
if (!active) {
|
||||
return;
|
||||
}
|
||||
|
||||
const mapStage = mapStageRef.current;
|
||||
|
||||
function getBrushPosition() {
|
||||
const mapImage = mapStage.findOne("#mapImage");
|
||||
return getRelativePointerPositionNormalized(mapImage);
|
||||
}
|
||||
|
||||
function handleBrushDown() {
|
||||
onPointerDown && onPointerDown(getBrushPosition());
|
||||
}
|
||||
|
||||
function handleBrushMove() {
|
||||
onPointerMove && onPointerMove(getBrushPosition());
|
||||
}
|
||||
|
||||
function handleBrushUp() {
|
||||
onPointerMove && onPointerUp({ x: 0, y: 0 });
|
||||
}
|
||||
|
||||
interactionEmitter.on("dragStart", handleBrushDown);
|
||||
interactionEmitter.on("drag", handleBrushMove);
|
||||
interactionEmitter.on("dragEnd", handleBrushUp);
|
||||
|
||||
return () => {
|
||||
interactionEmitter.off("dragStart", handleBrushDown);
|
||||
interactionEmitter.off("drag", handleBrushMove);
|
||||
interactionEmitter.off("dragEnd", handleBrushUp);
|
||||
};
|
||||
});
|
||||
|
||||
const size = getStrokeWidth(2, gridSize, mapWidth, mapHeight);
|
||||
|
||||
return (
|
||||
<Group>
|
||||
{visible && (
|
||||
<Circle
|
||||
x={position.x * mapWidth}
|
||||
y={position.y * mapHeight}
|
||||
fill={colors.red}
|
||||
width={size}
|
||||
height={size}
|
||||
/>
|
||||
)}
|
||||
</Group>
|
||||
);
|
||||
}
|
||||
|
||||
export default MapPointer;
|
18
src/icons/PointerToolIcon.js
Normal file
18
src/icons/PointerToolIcon.js
Normal file
@ -0,0 +1,18 @@
|
||||
import React from "react";
|
||||
|
||||
function PointerToolIcon() {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
width="24"
|
||||
fill="currentcolor"
|
||||
>
|
||||
<path d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M4.793 17.55l5.3-5.3 3.25 3.25c.41.41 1.07.39 1.45-.04 5-6.04 7.376-9.187 7.13-9.44-.267-.267-2.88 2.14-7.84 7.22l-3.29-3.29a.996.996 0 00-1.41 0l-6.09 6.1a.996.996 0 000 1.41l.09.09c.39.39 1.03.39 1.41 0z" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
export default PointerToolIcon;
|
@ -427,6 +427,7 @@ function NetworkedMapAndTokens({ session }) {
|
||||
allowFogDrawing={canEditFogDrawing}
|
||||
allowMapChange={canChangeMap}
|
||||
disabledTokens={disabledMapTokens}
|
||||
session={session}
|
||||
/>
|
||||
<Tokens onMapTokenStateCreate={handleMapTokenStateCreate} />
|
||||
</>
|
||||
|
76
src/network/NetworkedMapPointer.js
Normal file
76
src/network/NetworkedMapPointer.js
Normal file
@ -0,0 +1,76 @@
|
||||
import React, { useState, useContext, useEffect } from "react";
|
||||
import { Group } from "react-konva";
|
||||
|
||||
import AuthContext from "../contexts/AuthContext";
|
||||
|
||||
import MapPointer from "../components/map/MapPointer";
|
||||
|
||||
function NetworkedMapPointer({ session, active, gridSize }) {
|
||||
const { userId } = useContext(AuthContext);
|
||||
const [pointerState, setPointerState] = useState({});
|
||||
|
||||
useEffect(() => {
|
||||
if (userId && !(userId in pointerState)) {
|
||||
setPointerState({
|
||||
[userId]: { position: { x: 0, y: 0 }, visible: false, id: userId },
|
||||
});
|
||||
}
|
||||
}, [userId, pointerState]);
|
||||
|
||||
function updateOwnPointerState(position, visible) {
|
||||
const update = { [userId]: { position, visible, id: userId } };
|
||||
setPointerState((prev) => ({
|
||||
...prev,
|
||||
...update,
|
||||
}));
|
||||
session.send("pointer", update);
|
||||
}
|
||||
|
||||
function handleOwnPointerDown(position) {
|
||||
updateOwnPointerState(position, true);
|
||||
}
|
||||
|
||||
function handleOwnPointerMove(position) {
|
||||
updateOwnPointerState(position, true);
|
||||
}
|
||||
|
||||
function handleOwnPointerUp(position) {
|
||||
updateOwnPointerState(position, false);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
function handlePeerData({ id, data }) {
|
||||
if (id === "pointer") {
|
||||
setPointerState((prev) => ({
|
||||
...prev,
|
||||
...data,
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
session.on("data", handlePeerData);
|
||||
|
||||
return () => {
|
||||
session.off("data", handlePeerData);
|
||||
};
|
||||
});
|
||||
|
||||
return (
|
||||
<Group>
|
||||
{Object.values(pointerState).map((pointer) => (
|
||||
<MapPointer
|
||||
key={pointer.id}
|
||||
gridSize={gridSize}
|
||||
active={pointer.id === userId ? active : false}
|
||||
position={pointer.position}
|
||||
visible={pointer.visible}
|
||||
onPointerDown={pointer.id === userId && handleOwnPointerDown}
|
||||
onPointerMove={pointer.id === userId && handleOwnPointerMove}
|
||||
onPointerUp={pointer.id === userId && handleOwnPointerUp}
|
||||
/>
|
||||
))}
|
||||
</Group>
|
||||
);
|
||||
}
|
||||
|
||||
export default NetworkedMapPointer;
|
Loading…
Reference in New Issue
Block a user