Added is vehicle checkbox and vehicle type tokens
This commit is contained in:
parent
00c24c34a4
commit
a8bd5ab672
@ -32,7 +32,7 @@ function Map({
|
|||||||
disabledTokens,
|
disabledTokens,
|
||||||
loading,
|
loading,
|
||||||
}) {
|
}) {
|
||||||
const { tokens } = useContext(TokenDataContext);
|
const { tokensById } = useContext(TokenDataContext);
|
||||||
|
|
||||||
const gridX = map && map.gridX;
|
const gridX = map && map.gridX;
|
||||||
const gridY = map && map.gridY;
|
const gridY = map && map.gridY;
|
||||||
@ -200,7 +200,7 @@ function Map({
|
|||||||
|
|
||||||
const [isTokenMenuOpen, setIsTokenMenuOpen] = useState(false);
|
const [isTokenMenuOpen, setIsTokenMenuOpen] = useState(false);
|
||||||
const [tokenMenuOptions, setTokenMenuOptions] = useState({});
|
const [tokenMenuOptions, setTokenMenuOptions] = useState({});
|
||||||
const [draggingTokenState, setDraggingTokenState] = useState();
|
const [draggingTokenOptions, setDraggingTokenOptions] = useState();
|
||||||
function handleTokenMenuOpen(tokenStateId, tokenImage) {
|
function handleTokenMenuOpen(tokenStateId, tokenImage) {
|
||||||
setTokenMenuOptions({ tokenStateId, tokenImage });
|
setTokenMenuOptions({ tokenStateId, tokenImage });
|
||||||
setIsTokenMenuOpen(true);
|
setIsTokenMenuOpen(true);
|
||||||
@ -208,20 +208,28 @@ function Map({
|
|||||||
|
|
||||||
const mapTokens =
|
const mapTokens =
|
||||||
mapState &&
|
mapState &&
|
||||||
Object.values(mapState.tokens).map((tokenState) => (
|
Object.values(mapState.tokens)
|
||||||
|
.sort(
|
||||||
|
(a, b) =>
|
||||||
|
tokensById[b.tokenId].isVehicle - tokensById[a.tokenId].isVehicle
|
||||||
|
) // Sort so vehicles render below other tokens
|
||||||
|
.map((tokenState) => (
|
||||||
<MapToken
|
<MapToken
|
||||||
key={tokenState.id}
|
key={tokenState.id}
|
||||||
token={tokens.find((token) => token.id === tokenState.tokenId)}
|
token={tokensById[tokenState.tokenId]}
|
||||||
tokenState={tokenState}
|
tokenState={tokenState}
|
||||||
tokenSizePercent={tokenSizePercent}
|
tokenSizePercent={tokenSizePercent}
|
||||||
onTokenStateChange={onMapTokenStateChange}
|
onTokenStateChange={onMapTokenStateChange}
|
||||||
onTokenMenuOpen={handleTokenMenuOpen}
|
onTokenMenuOpen={handleTokenMenuOpen}
|
||||||
onTokenDragStart={() => setDraggingTokenState(tokenState)}
|
onTokenDragStart={(e) =>
|
||||||
onTokenDragEnd={() => setDraggingTokenState(null)}
|
setDraggingTokenOptions({ tokenState, tokenImage: e.target })
|
||||||
|
}
|
||||||
|
onTokenDragEnd={() => setDraggingTokenOptions(null)}
|
||||||
draggable={
|
draggable={
|
||||||
(selectedToolId === "pan" || selectedToolId === "erase") &&
|
(selectedToolId === "pan" || selectedToolId === "erase") &&
|
||||||
!(tokenState.id in disabledTokens)
|
!(tokenState.id in disabledTokens)
|
||||||
}
|
}
|
||||||
|
mapState={mapState}
|
||||||
/>
|
/>
|
||||||
));
|
));
|
||||||
|
|
||||||
@ -235,12 +243,17 @@ function Map({
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
const tokenDragOverlay = draggingTokenState && (
|
const tokenDragOverlay = draggingTokenOptions && (
|
||||||
<TokenDragOverlay
|
<TokenDragOverlay
|
||||||
onTokenStateRemove={() => {
|
onTokenStateRemove={(state) => {
|
||||||
onMapTokenStateRemove(draggingTokenState);
|
onMapTokenStateRemove(state);
|
||||||
setDraggingTokenState(null);
|
setDraggingTokenOptions(null);
|
||||||
}}
|
}}
|
||||||
|
onTokenStateChange={onMapTokenStateChange}
|
||||||
|
tokenState={draggingTokenOptions && draggingTokenOptions.tokenState}
|
||||||
|
tokenImage={draggingTokenOptions && draggingTokenOptions.tokenImage}
|
||||||
|
token={tokensById[draggingTokenOptions.tokenState.tokenId]}
|
||||||
|
mapState={mapState}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@ function MapToken({
|
|||||||
onTokenDragStart,
|
onTokenDragStart,
|
||||||
onTokenDragEnd,
|
onTokenDragEnd,
|
||||||
draggable,
|
draggable,
|
||||||
|
mapState,
|
||||||
}) {
|
}) {
|
||||||
const { userId } = useContext(AuthContext);
|
const { userId } = useContext(AuthContext);
|
||||||
const {
|
const {
|
||||||
@ -41,15 +42,69 @@ function MapToken({
|
|||||||
}
|
}
|
||||||
}, [tokenSourceImage]);
|
}, [tokenSourceImage]);
|
||||||
|
|
||||||
|
function handleDragStart(event) {
|
||||||
|
const tokenImage = event.target;
|
||||||
|
const tokenImageRect = tokenImage.getClientRect();
|
||||||
|
|
||||||
|
if (token.isVehicle) {
|
||||||
|
// Find all other tokens on the map
|
||||||
|
const layer = tokenImage.getLayer();
|
||||||
|
const tokens = layer.find(".token");
|
||||||
|
for (let other of tokens) {
|
||||||
|
if (other === tokenImage) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const otherRect = other.getClientRect();
|
||||||
|
const otherCenter = {
|
||||||
|
x: otherRect.x + otherRect.width / 2,
|
||||||
|
y: otherRect.y + otherRect.height / 2,
|
||||||
|
};
|
||||||
|
// Check the other tokens center overlaps this tokens bounding box
|
||||||
|
if (
|
||||||
|
otherCenter.x > tokenImageRect.x &&
|
||||||
|
otherCenter.x < tokenImageRect.x + tokenImageRect.width &&
|
||||||
|
otherCenter.y > tokenImageRect.y &&
|
||||||
|
otherCenter.y < tokenImageRect.y + tokenImageRect.height
|
||||||
|
) {
|
||||||
|
// Save and restore token position after moving layer
|
||||||
|
const position = other.absolutePosition();
|
||||||
|
other.moveTo(tokenImage);
|
||||||
|
other.absolutePosition(position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onTokenDragStart(event);
|
||||||
|
}
|
||||||
|
|
||||||
function handleDragEnd(event) {
|
function handleDragEnd(event) {
|
||||||
|
const tokenImage = event.target;
|
||||||
|
|
||||||
|
if (token.isVehicle) {
|
||||||
|
const layer = tokenImage.getLayer();
|
||||||
|
const mountedTokens = tokenImage.find(".token");
|
||||||
|
for (let mountedToken of mountedTokens) {
|
||||||
|
// Save and restore token position after moving layer
|
||||||
|
const position = mountedToken.absolutePosition();
|
||||||
|
mountedToken.moveTo(layer);
|
||||||
|
mountedToken.absolutePosition(position);
|
||||||
|
onTokenStateChange({
|
||||||
|
...mapState.tokens[mountedToken.id()],
|
||||||
|
x: mountedToken.x() / mapWidth,
|
||||||
|
y: mountedToken.y() / mapHeight,
|
||||||
|
lastEditedBy: userId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setPreventMapInteraction(false);
|
setPreventMapInteraction(false);
|
||||||
onTokenStateChange({
|
onTokenStateChange({
|
||||||
...tokenState,
|
...tokenState,
|
||||||
x: event.target.x() / mapWidth,
|
x: tokenImage.x() / mapWidth,
|
||||||
y: event.target.y() / mapHeight,
|
y: tokenImage.y() / mapHeight,
|
||||||
lastEditedBy: userId,
|
lastEditedBy: userId,
|
||||||
});
|
});
|
||||||
onTokenDragEnd();
|
onTokenDragEnd(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleClick(event) {
|
function handleClick(event) {
|
||||||
@ -121,8 +176,10 @@ function MapToken({
|
|||||||
onTouchEnd={handlePointerUp}
|
onTouchEnd={handlePointerUp}
|
||||||
onClick={handleClick}
|
onClick={handleClick}
|
||||||
onDragEnd={handleDragEnd}
|
onDragEnd={handleDragEnd}
|
||||||
onDragStart={onTokenDragStart}
|
onDragStart={handleDragStart}
|
||||||
opacity={tokenOpacity}
|
opacity={tokenOpacity}
|
||||||
|
name={token.isVehicle ? "vehicle" : "token"}
|
||||||
|
id={tokenState.id}
|
||||||
>
|
>
|
||||||
<KonvaImage
|
<KonvaImage
|
||||||
ref={imageRef}
|
ref={imageRef}
|
||||||
|
@ -3,13 +3,41 @@ import { Box, IconButton } from "theme-ui";
|
|||||||
|
|
||||||
import RemoveTokenIcon from "../../icons/RemoveTokenIcon";
|
import RemoveTokenIcon from "../../icons/RemoveTokenIcon";
|
||||||
|
|
||||||
|
import AuthContext from "../../contexts/AuthContext";
|
||||||
import MapInteractionContext from "../../contexts/MapInteractionContext";
|
import MapInteractionContext from "../../contexts/MapInteractionContext";
|
||||||
|
|
||||||
function TokenDragOverlay({ onTokenStateRemove }) {
|
function TokenDragOverlay({
|
||||||
const { setPreventMapInteraction } = useContext(MapInteractionContext);
|
onTokenStateRemove,
|
||||||
|
onTokenStateChange,
|
||||||
|
token,
|
||||||
|
tokenState,
|
||||||
|
tokenImage,
|
||||||
|
mapState,
|
||||||
|
}) {
|
||||||
|
const { userId } = useContext(AuthContext);
|
||||||
|
const { setPreventMapInteraction, mapWidth, mapHeight } = useContext(
|
||||||
|
MapInteractionContext
|
||||||
|
);
|
||||||
|
|
||||||
function handleTokenRemove() {
|
function handleTokenRemove() {
|
||||||
onTokenStateRemove();
|
// Handle other tokens when a vehicle gets deleted
|
||||||
|
if (token.isVehicle) {
|
||||||
|
const layer = tokenImage.getLayer();
|
||||||
|
const mountedTokens = tokenImage.find(".token");
|
||||||
|
for (let mountedToken of mountedTokens) {
|
||||||
|
// Save and restore token position after moving layer
|
||||||
|
const position = mountedToken.absolutePosition();
|
||||||
|
mountedToken.moveTo(layer);
|
||||||
|
mountedToken.absolutePosition(position);
|
||||||
|
onTokenStateChange({
|
||||||
|
...mapState.tokens[mountedToken.id()],
|
||||||
|
x: mountedToken.x() / mapWidth,
|
||||||
|
y: mountedToken.y() / mapHeight,
|
||||||
|
lastEditedBy: userId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onTokenStateRemove(tokenState);
|
||||||
setPreventMapInteraction(false);
|
setPreventMapInteraction(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { Flex, Box, Input, IconButton, Label } from "theme-ui";
|
import { Flex, Box, Input, IconButton, Label, Checkbox } from "theme-ui";
|
||||||
|
|
||||||
import ExpandMoreIcon from "../../icons/ExpandMoreIcon";
|
import ExpandMoreIcon from "../../icons/ExpandMoreIcon";
|
||||||
|
|
||||||
@ -29,7 +29,7 @@ function TokenSettings({
|
|||||||
</Flex>
|
</Flex>
|
||||||
{showMore && (
|
{showMore && (
|
||||||
<>
|
<>
|
||||||
<Box my={2} sx={{ flexGrow: 1 }}>
|
<Box mt={2} sx={{ flexGrow: 1 }}>
|
||||||
<Label htmlFor="name">Name</Label>
|
<Label htmlFor="name">Name</Label>
|
||||||
<Input
|
<Input
|
||||||
name="name"
|
name="name"
|
||||||
@ -39,6 +39,18 @@ function TokenSettings({
|
|||||||
my={1}
|
my={1}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
|
<Box my={2}>
|
||||||
|
<Label>
|
||||||
|
<Checkbox
|
||||||
|
checked={token && token.isVehicle}
|
||||||
|
disabled={!token || token.type === "default"}
|
||||||
|
onChange={(e) =>
|
||||||
|
onSettingsChange("isVehicle", e.target.checked)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
Vehicle / Mount
|
||||||
|
</Label>
|
||||||
|
</Box>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<IconButton
|
<IconButton
|
||||||
|
@ -86,6 +86,11 @@ export function TokenDataProvider({ children }) {
|
|||||||
|
|
||||||
const ownedTokens = tokens.filter((token) => token.owner === userId);
|
const ownedTokens = tokens.filter((token) => token.owner === userId);
|
||||||
|
|
||||||
|
const tokensById = tokens.reduce((obj, token) => {
|
||||||
|
obj[token.id] = token;
|
||||||
|
return obj;
|
||||||
|
}, {});
|
||||||
|
|
||||||
const value = {
|
const value = {
|
||||||
tokens,
|
tokens,
|
||||||
ownedTokens,
|
ownedTokens,
|
||||||
@ -94,6 +99,7 @@ export function TokenDataProvider({ children }) {
|
|||||||
updateToken,
|
updateToken,
|
||||||
putToken,
|
putToken,
|
||||||
getToken,
|
getToken,
|
||||||
|
tokensById,
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -64,6 +64,7 @@ function SelectTokensModal({ isOpen, onRequestClose }) {
|
|||||||
lastModified: Date.now(),
|
lastModified: Date.now(),
|
||||||
owner: userId,
|
owner: userId,
|
||||||
defaultSize: 1,
|
defaultSize: 1,
|
||||||
|
isVehicle: false,
|
||||||
});
|
});
|
||||||
setImageLoading(false);
|
setImageLoading(false);
|
||||||
};
|
};
|
||||||
|
@ -85,6 +85,7 @@ export const tokens = Object.keys(tokenSources).map((key) => ({
|
|||||||
name: Case.capital(key),
|
name: Case.capital(key),
|
||||||
type: "default",
|
type: "default",
|
||||||
defaultSize: getDefaultTokenSize(key),
|
defaultSize: getDefaultTokenSize(key),
|
||||||
|
isVehicle: false,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export const unknownSource = unknown;
|
export const unknownSource = unknown;
|
||||||
|
Loading…
Reference in New Issue
Block a user