Added simple pointer tool

This commit is contained in:
Mitchell McCaffrey 2020-07-28 17:59:26 +10:00
parent 9efc84434b
commit c6f9b29cc3
6 changed files with 195 additions and 1 deletions

View File

@ -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>
);

View File

@ -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 = [
{

View 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;

View 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;

View File

@ -427,6 +427,7 @@ function NetworkedMapAndTokens({ session }) {
allowFogDrawing={canEditFogDrawing}
allowMapChange={canChangeMap}
disabledTokens={disabledMapTokens}
session={session}
/>
<Tokens onMapTokenStateCreate={handleMapTokenStateCreate} />
</>

View 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;