Added token moving and removing on map

This commit is contained in:
Mitchell McCaffrey 2020-03-20 13:33:12 +11:00
parent 1133fe2d2b
commit 82d750eca7
6 changed files with 105 additions and 44 deletions

View File

@ -2,37 +2,60 @@ import React from "react";
import { Image, Flex, Box } from "theme-ui"; import { Image, Flex, Box } from "theme-ui";
import Token from "../components/Token"; import Token from "../components/Token";
import ProxyToken from "../components/ProxyToken";
const mapTokenClassName = "map-token";
function Map({ imageSource, tokens, onMapTokenMove, onMapTokenRemove }) {
function handleProxyDragEnd(isOnMap, token) {
if (isOnMap && onMapTokenMove) {
onMapTokenMove(token);
}
if (!isOnMap && onMapTokenRemove) {
onMapTokenRemove(token);
}
}
function Map({ imageSource, tokens }) {
return ( return (
<Flex <>
className="map" <Flex
sx={{ justifyContent: "center", flexGrow: 1 }} className="map"
bg="background" sx={{ justifyContent: "center", flexGrow: 1 }}
> bg="background"
<Box
sx={{
position: "absolute",
top: 0,
left: 0,
right: 0,
userSelect: "none"
}}
> >
{Object.values(tokens).map(token => ( <Box
<Box sx={{
key={token.id} position: "absolute",
sx={{ top: 0,
position: "absolute", left: 0,
transform: `translate(${token.x}px, ${token.y}px)` right: 0,
}} userSelect: "none"
> }}
<Token image={token.image} className="map-token" /> >
</Box> {Object.values(tokens).map(token => (
))} <Box
</Box> key={token.id}
<Image src={imageSource} sx={{ objectFit: "contain" }} /> sx={{
</Flex> position: "absolute",
transform: `translate(${token.x}px, ${token.y}px)`
}}
>
<Token
tokenId={token.id}
image={token.image}
className={mapTokenClassName}
/>
</Box>
))}
</Box>
<Image src={imageSource} sx={{ objectFit: "contain" }} />
</Flex>
<ProxyToken
tokenClassName={mapTokenClassName}
onProxyDragEnd={handleProxyDragEnd}
/>
</>
); );
} }

View File

@ -67,12 +67,14 @@ function ProxyToken({ tokenClassName, onProxyDragEnd }) {
let proxy = imageRef.current; let proxy = imageRef.current;
if (proxy) { if (proxy) {
if (onProxyDragEnd) { if (onProxyDragEnd) {
const endX = parseFloat(proxy.getAttribute("data-x")) || 0; const x = parseFloat(proxy.getAttribute("data-x")) || 0;
const endY = parseFloat(proxy.getAttribute("data-y")) || 0; const y = parseFloat(proxy.getAttribute("data-y")) || 0;
const id = target.getAttribute("data-token-id");
onProxyDragEnd(proxyOnMap.current, { onProxyDragEnd(proxyOnMap.current, {
image: imageSource, image: imageSource,
x: endX, x,
y: endY y,
id
}); });
} }

View File

@ -1,7 +1,9 @@
import React from "react"; import React from "react";
import { Image } from "theme-ui"; import { Image } from "theme-ui";
function Token({ image, className }) { function Token({ image, className, tokenId }) {
// Store the token id in the html element for the drag code to pick it up
const idProp = tokenId ? { "data-token-id": tokenId } : {};
return ( return (
<Image <Image
p={2} p={2}
@ -11,6 +13,7 @@ function Token({ image, className }) {
width: "64px", width: "64px",
height: "64px" height: "64px"
}} }}
{...idProp}
/> />
); );
} }

View File

@ -7,13 +7,13 @@ import * as tokens from "../tokens";
import Token from "./Token"; import Token from "./Token";
import ProxyToken from "./ProxyToken"; import ProxyToken from "./ProxyToken";
function Tokens({ onCreateMapToken }) { const listTokenClassName = "list-token";
const tokenClassName = "list-token";
function Tokens({ onCreateMapToken }) {
function handleProxyDragEnd(isOnMap, token) { function handleProxyDragEnd(isOnMap, token) {
if (isOnMap && onCreateMapToken) { if (isOnMap && onCreateMapToken) {
// Give the token an id // Give the token an id
onCreateMapToken({ id: shortid.generate(), ...token }); onCreateMapToken({ ...token, id: shortid.generate() });
} }
} }
@ -30,11 +30,11 @@ function Tokens({ onCreateMapToken }) {
px={2} px={2}
> >
{Object.entries(tokens).map(([id, image]) => ( {Object.entries(tokens).map(([id, image]) => (
<Token key={id} image={image} className={tokenClassName} /> <Token key={id} image={image} className={listTokenClassName} />
))} ))}
</Flex> </Flex>
<ProxyToken <ProxyToken
tokenClassName={tokenClassName} tokenClassName={listTokenClassName}
onProxyDragEnd={handleProxyDragEnd} onProxyDragEnd={handleProxyDragEnd}
/> />
</> </>

10
src/helpers/shared.js Normal file
View File

@ -0,0 +1,10 @@
export function omit(obj, keys) {
let tmp = {};
for (let [key, value] of Object.entries(obj)) {
if (keys.includes(key)) {
continue;
}
tmp[key] = value;
}
return tmp;
}

View File

@ -7,6 +7,8 @@ import React, {
} from "react"; } from "react";
import { Box, Flex } from "theme-ui"; import { Box, Flex } from "theme-ui";
import { omit } from "../helpers/shared";
import GameContext from "../contexts/GameContext"; import GameContext from "../contexts/GameContext";
import useSession from "../helpers/useSession"; import useSession from "../helpers/useSession";
@ -43,14 +45,25 @@ function Game() {
const [mapTokens, setMapTokens] = useState({}); const [mapTokens, setMapTokens] = useState({});
function handleCreateMapToken(token) { function handleEditMapToken(token) {
setMapTokens(prevMapTokens => ({ setMapTokens(prevMapTokens => ({
...prevMapTokens, ...prevMapTokens,
[token.id]: token [token.id]: token
})); }));
for (let connection of Object.values(connections)) { for (let connection of Object.values(connections)) {
const data = { [token.id]: token }; const data = { [token.id]: token };
connection.send({ id: "token", data }); connection.send({ id: "tokenEdit", data });
}
}
function handleRemoveMapToken(token) {
setMapTokens(prevMapTokens => {
const { [token.id]: old, ...rest } = prevMapTokens;
return rest;
});
for (let connection of Object.values(connections)) {
const data = { [token.id]: token };
connection.send({ id: "tokenRemove", data });
} }
} }
@ -61,12 +74,17 @@ function Game() {
imageDataRef.current = blob; imageDataRef.current = blob;
setImageSource(URL.createObjectURL(imageDataRef.current)); setImageSource(URL.createObjectURL(imageDataRef.current));
} }
if (data.id === "token") { if (data.id === "tokenEdit") {
setMapTokens(prevMapTokens => ({ setMapTokens(prevMapTokens => ({
...prevMapTokens, ...prevMapTokens,
...data.data ...data.data
})); }));
} }
if (data.id === "tokenRemove") {
setMapTokens(prevMapTokens =>
omit(prevMapTokens, Object.keys(data.data))
);
}
}); });
} }
@ -74,7 +92,7 @@ function Game() {
if (imageSource) { if (imageSource) {
connection.send({ id: "image", data: imageDataRef.current }); connection.send({ id: "image", data: imageDataRef.current });
} }
connection.send({ id: "token", data: mapTokens }); connection.send({ id: "tokenEdit", data: mapTokens });
} }
return ( return (
@ -94,8 +112,13 @@ function Game() {
sx={{ justifyContent: "space-between", flexGrow: 1, height: "100%" }} sx={{ justifyContent: "space-between", flexGrow: 1, height: "100%" }}
> >
<Party streams={streams} localStreamId={peerId} /> <Party streams={streams} localStreamId={peerId} />
<Map imageSource={imageSource} tokens={mapTokens} /> <Map
<Tokens onCreateMapToken={handleCreateMapToken} /> imageSource={imageSource}
tokens={mapTokens}
onMapTokenMove={handleEditMapToken}
onMapTokenRemove={handleRemoveMapToken}
/>
<Tokens onCreateMapToken={handleEditMapToken} />
</Flex> </Flex>
</Flex> </Flex>
); );