From a8bd5ab672f78b0f20db2537576386c8d0f0d5da Mon Sep 17 00:00:00 2001 From: Mitchell McCaffrey Date: Fri, 22 May 2020 20:43:07 +1000 Subject: [PATCH] Added is vehicle checkbox and vehicle type tokens --- src/components/map/Map.js | 57 +++++++++++++-------- src/components/map/MapToken.js | 65 ++++++++++++++++++++++-- src/components/token/TokenDragOverlay.js | 34 +++++++++++-- src/components/token/TokenSettings.js | 16 +++++- src/contexts/TokenDataContext.js | 6 +++ src/modals/SelectTokensModal.js | 1 + src/tokens/index.js | 1 + 7 files changed, 149 insertions(+), 31 deletions(-) diff --git a/src/components/map/Map.js b/src/components/map/Map.js index 607761a..7c73cd3 100644 --- a/src/components/map/Map.js +++ b/src/components/map/Map.js @@ -32,7 +32,7 @@ function Map({ disabledTokens, loading, }) { - const { tokens } = useContext(TokenDataContext); + const { tokensById } = useContext(TokenDataContext); const gridX = map && map.gridX; const gridY = map && map.gridY; @@ -200,7 +200,7 @@ function Map({ const [isTokenMenuOpen, setIsTokenMenuOpen] = useState(false); const [tokenMenuOptions, setTokenMenuOptions] = useState({}); - const [draggingTokenState, setDraggingTokenState] = useState(); + const [draggingTokenOptions, setDraggingTokenOptions] = useState(); function handleTokenMenuOpen(tokenStateId, tokenImage) { setTokenMenuOptions({ tokenStateId, tokenImage }); setIsTokenMenuOpen(true); @@ -208,22 +208,30 @@ function Map({ const mapTokens = mapState && - Object.values(mapState.tokens).map((tokenState) => ( - token.id === tokenState.tokenId)} - tokenState={tokenState} - tokenSizePercent={tokenSizePercent} - onTokenStateChange={onMapTokenStateChange} - onTokenMenuOpen={handleTokenMenuOpen} - onTokenDragStart={() => setDraggingTokenState(tokenState)} - onTokenDragEnd={() => setDraggingTokenState(null)} - draggable={ - (selectedToolId === "pan" || selectedToolId === "erase") && - !(tokenState.id in disabledTokens) - } - /> - )); + Object.values(mapState.tokens) + .sort( + (a, b) => + tokensById[b.tokenId].isVehicle - tokensById[a.tokenId].isVehicle + ) // Sort so vehicles render below other tokens + .map((tokenState) => ( + + setDraggingTokenOptions({ tokenState, tokenImage: e.target }) + } + onTokenDragEnd={() => setDraggingTokenOptions(null)} + draggable={ + (selectedToolId === "pan" || selectedToolId === "erase") && + !(tokenState.id in disabledTokens) + } + mapState={mapState} + /> + )); const tokenMenu = ( ); - const tokenDragOverlay = draggingTokenState && ( + const tokenDragOverlay = draggingTokenOptions && ( { - onMapTokenStateRemove(draggingTokenState); - setDraggingTokenState(null); + onTokenStateRemove={(state) => { + onMapTokenStateRemove(state); + setDraggingTokenOptions(null); }} + onTokenStateChange={onMapTokenStateChange} + tokenState={draggingTokenOptions && draggingTokenOptions.tokenState} + tokenImage={draggingTokenOptions && draggingTokenOptions.tokenImage} + token={tokensById[draggingTokenOptions.tokenState.tokenId]} + mapState={mapState} /> ); diff --git a/src/components/map/MapToken.js b/src/components/map/MapToken.js index 57dcb58..bed4815 100644 --- a/src/components/map/MapToken.js +++ b/src/components/map/MapToken.js @@ -22,6 +22,7 @@ function MapToken({ onTokenDragStart, onTokenDragEnd, draggable, + mapState, }) { const { userId } = useContext(AuthContext); const { @@ -41,15 +42,69 @@ function MapToken({ } }, [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) { + 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); onTokenStateChange({ ...tokenState, - x: event.target.x() / mapWidth, - y: event.target.y() / mapHeight, + x: tokenImage.x() / mapWidth, + y: tokenImage.y() / mapHeight, lastEditedBy: userId, }); - onTokenDragEnd(); + onTokenDragEnd(event); } function handleClick(event) { @@ -121,8 +176,10 @@ function MapToken({ onTouchEnd={handlePointerUp} onClick={handleClick} onDragEnd={handleDragEnd} - onDragStart={onTokenDragStart} + onDragStart={handleDragStart} opacity={tokenOpacity} + name={token.isVehicle ? "vehicle" : "token"} + id={tokenState.id} > {showMore && ( <> - + + + + )} token.owner === userId); + const tokensById = tokens.reduce((obj, token) => { + obj[token.id] = token; + return obj; + }, {}); + const value = { tokens, ownedTokens, @@ -94,6 +99,7 @@ export function TokenDataProvider({ children }) { updateToken, putToken, getToken, + tokensById, }; return ( diff --git a/src/modals/SelectTokensModal.js b/src/modals/SelectTokensModal.js index f89ebe7..751f721 100644 --- a/src/modals/SelectTokensModal.js +++ b/src/modals/SelectTokensModal.js @@ -64,6 +64,7 @@ function SelectTokensModal({ isOpen, onRequestClose }) { lastModified: Date.now(), owner: userId, defaultSize: 1, + isVehicle: false, }); setImageLoading(false); }; diff --git a/src/tokens/index.js b/src/tokens/index.js index eb02e7f..88c8881 100644 --- a/src/tokens/index.js +++ b/src/tokens/index.js @@ -85,6 +85,7 @@ export const tokens = Object.keys(tokenSources).map((key) => ({ name: Case.capital(key), type: "default", defaultSize: getDefaultTokenSize(key), + isVehicle: false, })); export const unknownSource = unknown;