Added multiple map layout and basic data flow
This commit is contained in:
parent
f2a92f2ccd
commit
22c5b5cf75
@ -1,11 +1,9 @@
|
|||||||
import React, { useRef, useState, useEffect } from "react";
|
import React, { useState } from "react";
|
||||||
import { IconButton } from "theme-ui";
|
import { IconButton } from "theme-ui";
|
||||||
|
|
||||||
import AddMapModal from "../../modals/AddMapModal";
|
import AddMapModal from "../../modals/AddMapModal";
|
||||||
import AddMapIcon from "../../icons/AddMapIcon";
|
import AddMapIcon from "../../icons/AddMapIcon";
|
||||||
|
|
||||||
const defaultMapSize = 22;
|
|
||||||
|
|
||||||
function AddMapButton({ onMapChange }) {
|
function AddMapButton({ onMapChange }) {
|
||||||
const [isAddModalOpen, setIsAddModalOpen] = useState(false);
|
const [isAddModalOpen, setIsAddModalOpen] = useState(false);
|
||||||
function openModal() {
|
function openModal() {
|
||||||
@ -15,49 +13,11 @@ function AddMapButton({ onMapChange }) {
|
|||||||
setIsAddModalOpen(false);
|
setIsAddModalOpen(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
const [imageLoaded, setImageLoaded] = useState(false);
|
function handleDone(map) {
|
||||||
|
onMapChange(map);
|
||||||
const mapDataRef = useRef(null);
|
|
||||||
const [mapSource, setMapSource] = useState(null);
|
|
||||||
function handleImageUpload(file, fileGridX, fileGridY) {
|
|
||||||
const url = URL.createObjectURL(file);
|
|
||||||
let image = new Image();
|
|
||||||
image.onload = function () {
|
|
||||||
mapDataRef.current = {
|
|
||||||
file,
|
|
||||||
gridX: fileGridX || gridX,
|
|
||||||
gridY: fileGridY || gridY,
|
|
||||||
width: image.width,
|
|
||||||
height: image.height,
|
|
||||||
};
|
|
||||||
setImageLoaded(true);
|
|
||||||
};
|
|
||||||
image.src = url;
|
|
||||||
setMapSource(url);
|
|
||||||
if (fileGridX) {
|
|
||||||
setGridX(fileGridX);
|
|
||||||
}
|
|
||||||
if (fileGridY) {
|
|
||||||
setGridY(fileGridY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleDone() {
|
|
||||||
if (mapDataRef.current && mapSource) {
|
|
||||||
onMapChange(mapDataRef.current, mapSource);
|
|
||||||
}
|
|
||||||
closeModal();
|
closeModal();
|
||||||
}
|
}
|
||||||
|
|
||||||
const [gridX, setGridX] = useState(defaultMapSize);
|
|
||||||
const [gridY, setGridY] = useState(defaultMapSize);
|
|
||||||
useEffect(() => {
|
|
||||||
if (mapDataRef.current) {
|
|
||||||
mapDataRef.current.gridX = gridX;
|
|
||||||
mapDataRef.current.gridY = gridY;
|
|
||||||
}
|
|
||||||
}, [gridX, gridY]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<IconButton aria-label="Add Map" title="Add Map" onClick={openModal}>
|
<IconButton aria-label="Add Map" title="Add Map" onClick={openModal}>
|
||||||
@ -67,13 +27,6 @@ function AddMapButton({ onMapChange }) {
|
|||||||
isOpen={isAddModalOpen}
|
isOpen={isAddModalOpen}
|
||||||
onRequestClose={closeModal}
|
onRequestClose={closeModal}
|
||||||
onDone={handleDone}
|
onDone={handleDone}
|
||||||
onImageUpload={handleImageUpload}
|
|
||||||
gridX={gridX}
|
|
||||||
onGridXChange={setGridX}
|
|
||||||
gridY={gridY}
|
|
||||||
onGridYChange={setGridY}
|
|
||||||
imageLoaded={imageLoaded}
|
|
||||||
mapSource={mapSource}
|
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
@ -17,8 +17,7 @@ const minZoom = 0.1;
|
|||||||
const maxZoom = 5;
|
const maxZoom = 5;
|
||||||
|
|
||||||
function Map({
|
function Map({
|
||||||
mapSource,
|
map,
|
||||||
mapData,
|
|
||||||
tokens,
|
tokens,
|
||||||
onMapTokenChange,
|
onMapTokenChange,
|
||||||
onMapTokenRemove,
|
onMapTokenRemove,
|
||||||
@ -80,7 +79,7 @@ function Map({
|
|||||||
}, [drawActions, drawActionIndex]);
|
}, [drawActions, drawActionIndex]);
|
||||||
|
|
||||||
const disabledTools = [];
|
const disabledTools = [];
|
||||||
if (!mapData) {
|
if (!map) {
|
||||||
disabledTools.push("pan");
|
disabledTools.push("pan");
|
||||||
disabledTools.push("brush");
|
disabledTools.push("brush");
|
||||||
}
|
}
|
||||||
@ -134,7 +133,7 @@ function Map({
|
|||||||
move: (e) => handleMove(e, false),
|
move: (e) => handleMove(e, false),
|
||||||
},
|
},
|
||||||
cursorChecker: () => {
|
cursorChecker: () => {
|
||||||
return selectedTool === "pan" && mapData ? "move" : "default";
|
return selectedTool === "pan" && map ? "move" : "default";
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.on("doubletap", (event) => {
|
.on("doubletap", (event) => {
|
||||||
@ -147,12 +146,12 @@ function Map({
|
|||||||
return () => {
|
return () => {
|
||||||
mapInteract.unset();
|
mapInteract.unset();
|
||||||
};
|
};
|
||||||
}, [selectedTool, mapData]);
|
}, [selectedTool, map]);
|
||||||
|
|
||||||
// Reset map transform when map changes
|
// Reset map transform when map changes
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setTranslateAndScale({ x: 0, y: 0 }, 1);
|
setTranslateAndScale({ x: 0, y: 0 }, 1);
|
||||||
}, [mapSource]);
|
}, [map]);
|
||||||
|
|
||||||
// Bind the wheel event of the map via a ref
|
// Bind the wheel event of the map via a ref
|
||||||
// in order to support non-passive event listening
|
// in order to support non-passive event listening
|
||||||
@ -194,11 +193,11 @@ function Map({
|
|||||||
|
|
||||||
const mapRef = useRef(null);
|
const mapRef = useRef(null);
|
||||||
const mapContainerRef = useRef();
|
const mapContainerRef = useRef();
|
||||||
const gridX = mapData && mapData.gridX;
|
const gridX = map && map.gridX;
|
||||||
const gridY = mapData && mapData.gridY;
|
const gridY = map && map.gridY;
|
||||||
const gridSizeNormalized = { x: 1 / gridX || 0, y: 1 / gridY || 0 };
|
const gridSizeNormalized = { x: 1 / gridX || 0, y: 1 / gridY || 0 };
|
||||||
const tokenSizePercent = gridSizeNormalized.x * 100;
|
const tokenSizePercent = gridSizeNormalized.x * 100;
|
||||||
const aspectRatio = (mapData && mapData.width / mapData.height) || 1;
|
const aspectRatio = (map && map.width / map.height) || 1;
|
||||||
|
|
||||||
const mapImage = (
|
const mapImage = (
|
||||||
<Box
|
<Box
|
||||||
@ -218,7 +217,7 @@ function Map({
|
|||||||
userSelect: "none",
|
userSelect: "none",
|
||||||
touchAction: "none",
|
touchAction: "none",
|
||||||
}}
|
}}
|
||||||
src={mapSource}
|
src={map && map.source}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
@ -278,8 +277,8 @@ function Map({
|
|||||||
/>
|
/>
|
||||||
{mapImage}
|
{mapImage}
|
||||||
<MapDrawing
|
<MapDrawing
|
||||||
width={mapData ? mapData.width : 0}
|
width={map ? map.width : 0}
|
||||||
height={mapData ? mapData.height : 0}
|
height={map ? map.height : 0}
|
||||||
selectedTool={selectedTool}
|
selectedTool={selectedTool}
|
||||||
shapes={drawnShapes}
|
shapes={drawnShapes}
|
||||||
onShapeAdd={handleShapeAdd}
|
onShapeAdd={handleShapeAdd}
|
||||||
|
55
src/components/map/MapSelect.js
Normal file
55
src/components/map/MapSelect.js
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
import React from "react";
|
||||||
|
import { Flex, Image as UIImage } from "theme-ui";
|
||||||
|
|
||||||
|
import AddIcon from "../../icons/AddIcon";
|
||||||
|
|
||||||
|
function MapSelect({ maps, onMapAdd }) {
|
||||||
|
const tileProps = {
|
||||||
|
m: 2,
|
||||||
|
sx: {
|
||||||
|
width: "150px",
|
||||||
|
height: "150px",
|
||||||
|
borderRadius: "4px",
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "center",
|
||||||
|
},
|
||||||
|
bg: "muted",
|
||||||
|
};
|
||||||
|
|
||||||
|
function tile(map) {
|
||||||
|
return (
|
||||||
|
<Flex // TODO: use DB key
|
||||||
|
key={map.source}
|
||||||
|
{...tileProps}
|
||||||
|
>
|
||||||
|
<UIImage
|
||||||
|
sx={{ width: "100%", objectFit: "contain" }}
|
||||||
|
src={map.source}
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Flex
|
||||||
|
my={2}
|
||||||
|
bg="muted"
|
||||||
|
sx={{
|
||||||
|
flexWrap: "wrap",
|
||||||
|
width: "500px",
|
||||||
|
maxHeight: "300px",
|
||||||
|
borderRadius: "4px",
|
||||||
|
// TODO: move to simple scroll
|
||||||
|
overflowY: "scroll",
|
||||||
|
flexGrow: 1,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{maps.map(tile)}
|
||||||
|
<Flex onClick={onMapAdd} {...tileProps}>
|
||||||
|
<AddIcon />
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MapSelect;
|
18
src/icons/AddIcon.js
Normal file
18
src/icons/AddIcon.js
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import React from "react";
|
||||||
|
|
||||||
|
function AddIcon() {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
height="24"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
width="24"
|
||||||
|
fill="currentcolor"
|
||||||
|
>
|
||||||
|
<path d="M0 0h24v24H0V0z" fill="none" />
|
||||||
|
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm4 11h-3v3c0 .55-.45 1-1 1s-1-.45-1-1v-3H8c-.55 0-1-.45-1-1s.45-1 1-1h3V8c0-.55.45-1 1-1s1 .45 1 1v3h3c.55 0 1 .45 1 1s-.45 1-1 1z" />
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AddIcon;
|
BIN
src/maps/Blank Grid 22x22.jpg
Executable file
BIN
src/maps/Blank Grid 22x22.jpg
Executable file
Binary file not shown.
After Width: | Height: | Size: 89 KiB |
BIN
src/maps/Grass Grid 22x22.jpg
Executable file
BIN
src/maps/Grass Grid 22x22.jpg
Executable file
Binary file not shown.
After Width: | Height: | Size: 106 KiB |
BIN
src/maps/Sand Grid 22x22.jpg
Executable file
BIN
src/maps/Sand Grid 22x22.jpg
Executable file
Binary file not shown.
After Width: | Height: | Size: 110 KiB |
BIN
src/maps/Stone Grid 22x22.jpg
Executable file
BIN
src/maps/Stone Grid 22x22.jpg
Executable file
Binary file not shown.
After Width: | Height: | Size: 169 KiB |
BIN
src/maps/Water Grid 22x22.jpg
Executable file
BIN
src/maps/Water Grid 22x22.jpg
Executable file
Binary file not shown.
After Width: | Height: | Size: 171 KiB |
BIN
src/maps/Wood Grid 22x22.jpg
Executable file
BIN
src/maps/Wood Grid 22x22.jpg
Executable file
Binary file not shown.
After Width: | Height: | Size: 180 KiB |
49
src/maps/index.js
Normal file
49
src/maps/index.js
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import blankImage from "./Blank Grid 22x22.jpg";
|
||||||
|
import grassImage from "./Grass Grid 22x22.jpg";
|
||||||
|
import sandImage from "./Sand Grid 22x22.jpg";
|
||||||
|
import stoneImage from "./Stone Grid 22x22.jpg";
|
||||||
|
import waterImage from "./Water Grid 22x22.jpg";
|
||||||
|
import woodImage from "./Wood Grid 22x22.jpg";
|
||||||
|
|
||||||
|
const defaultProps = {
|
||||||
|
gridX: 22,
|
||||||
|
gridY: 22,
|
||||||
|
width: 1024,
|
||||||
|
height: 1024,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const blank = {
|
||||||
|
...defaultProps,
|
||||||
|
source: blankImage,
|
||||||
|
name: "Blank Grid 22x22",
|
||||||
|
};
|
||||||
|
|
||||||
|
export const grass = {
|
||||||
|
...defaultProps,
|
||||||
|
source: grassImage,
|
||||||
|
name: "Grass Grid 22x22",
|
||||||
|
};
|
||||||
|
|
||||||
|
export const sand = {
|
||||||
|
...defaultProps,
|
||||||
|
source: sandImage,
|
||||||
|
name: "Sand Grid 22x22",
|
||||||
|
};
|
||||||
|
|
||||||
|
export const stone = {
|
||||||
|
...defaultProps,
|
||||||
|
source: stoneImage,
|
||||||
|
name: "Stone Grid 22x22",
|
||||||
|
};
|
||||||
|
|
||||||
|
export const water = {
|
||||||
|
...defaultProps,
|
||||||
|
source: waterImage,
|
||||||
|
name: "Water Grid 22x22",
|
||||||
|
};
|
||||||
|
|
||||||
|
export const wood = {
|
||||||
|
...defaultProps,
|
||||||
|
source: woodImage,
|
||||||
|
name: "Wood Grid 22x22",
|
||||||
|
};
|
@ -1,31 +1,41 @@
|
|||||||
import React, { useRef, useState } from "react";
|
import React, { useRef, useState, useEffect } from "react";
|
||||||
import {
|
import { Box, Button, Flex, Label, Input, Text } from "theme-ui";
|
||||||
Box,
|
|
||||||
Button,
|
|
||||||
Image as UIImage,
|
|
||||||
Flex,
|
|
||||||
Label,
|
|
||||||
Input,
|
|
||||||
Text,
|
|
||||||
} from "theme-ui";
|
|
||||||
|
|
||||||
import Modal from "../components/Modal";
|
import Modal from "../components/Modal";
|
||||||
|
import MapSelect from "../components/map/MapSelect";
|
||||||
|
|
||||||
|
import * as defaultMaps from "../maps";
|
||||||
|
|
||||||
|
const defaultMapSize = 22;
|
||||||
|
|
||||||
|
function AddMapModal({ isOpen, onRequestClose, onDone }) {
|
||||||
|
const [imageLoading, setImageLoading] = useState(false);
|
||||||
|
|
||||||
|
const [currentMap, setCurrentMap] = useState(-1);
|
||||||
|
const [maps, setMaps] = useState(Object.values(defaultMaps));
|
||||||
|
|
||||||
|
const [gridX, setGridX] = useState(defaultMapSize);
|
||||||
|
const [gridY, setGridY] = useState(defaultMapSize);
|
||||||
|
useEffect(() => {
|
||||||
|
setMaps((prevMaps) => {
|
||||||
|
const newMaps = [...prevMaps];
|
||||||
|
const changedMap = newMaps[currentMap];
|
||||||
|
if (changedMap) {
|
||||||
|
changedMap.gridX = gridX;
|
||||||
|
changedMap.gridY = gridY;
|
||||||
|
}
|
||||||
|
return newMaps;
|
||||||
|
});
|
||||||
|
}, [gridX, gridY, currentMap]);
|
||||||
|
|
||||||
function AddMapModal({
|
|
||||||
isOpen,
|
|
||||||
onRequestClose,
|
|
||||||
onDone,
|
|
||||||
onImageUpload,
|
|
||||||
gridX,
|
|
||||||
onGridXChange,
|
|
||||||
gridY,
|
|
||||||
onGridYChange,
|
|
||||||
imageLoaded,
|
|
||||||
mapSource,
|
|
||||||
}) {
|
|
||||||
const fileInputRef = useRef();
|
const fileInputRef = useRef();
|
||||||
|
|
||||||
function handleImageUpload(file) {
|
function handleImageUpload(file) {
|
||||||
|
if (!file) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let fileGridX = defaultMapSize;
|
||||||
|
let fileGridY = defaultMapSize;
|
||||||
if (file.name) {
|
if (file.name) {
|
||||||
// Match against a regex to find the grid size in the file name
|
// Match against a regex to find the grid size in the file name
|
||||||
// e.g. Cave 22x23 will return [["22x22", "22", "x", "23"]]
|
// e.g. Cave 22x23 will return [["22x22", "22", "x", "23"]]
|
||||||
@ -35,12 +45,35 @@ function AddMapModal({
|
|||||||
const matchX = parseInt(lastMatch[1]);
|
const matchX = parseInt(lastMatch[1]);
|
||||||
const matchY = parseInt(lastMatch[3]);
|
const matchY = parseInt(lastMatch[3]);
|
||||||
if (!isNaN(matchX) && !isNaN(matchY)) {
|
if (!isNaN(matchX) && !isNaN(matchY)) {
|
||||||
onImageUpload(file, matchX, matchY);
|
fileGridX = matchX;
|
||||||
return;
|
fileGridY = matchY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onImageUpload(file);
|
const url = URL.createObjectURL(file);
|
||||||
|
let image = new Image();
|
||||||
|
setImageLoading(true);
|
||||||
|
image.onload = function () {
|
||||||
|
setMaps((prevMaps) => {
|
||||||
|
const newMaps = [
|
||||||
|
...prevMaps,
|
||||||
|
{
|
||||||
|
file,
|
||||||
|
gridX: fileGridX,
|
||||||
|
gridY: fileGridY,
|
||||||
|
width: image.width,
|
||||||
|
height: image.height,
|
||||||
|
source: url,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
setCurrentMap(newMaps.length - 1);
|
||||||
|
return newMaps;
|
||||||
|
});
|
||||||
|
setGridX(fileGridX);
|
||||||
|
setGridY(fileGridY);
|
||||||
|
setImageLoading(false);
|
||||||
|
};
|
||||||
|
image.src = url;
|
||||||
}
|
}
|
||||||
|
|
||||||
function openImageDialog() {
|
function openImageDialog() {
|
||||||
@ -78,7 +111,7 @@ function AddMapModal({
|
|||||||
as="form"
|
as="form"
|
||||||
onSubmit={(e) => {
|
onSubmit={(e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
onDone();
|
onDone(maps[currentMap]);
|
||||||
}}
|
}}
|
||||||
onDragEnter={handleImageDragEnter}
|
onDragEnter={handleImageDragEnter}
|
||||||
>
|
>
|
||||||
@ -89,7 +122,6 @@ function AddMapModal({
|
|||||||
style={{ display: "none" }}
|
style={{ display: "none" }}
|
||||||
ref={fileInputRef}
|
ref={fileInputRef}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Flex
|
<Flex
|
||||||
sx={{
|
sx={{
|
||||||
flexDirection: "column",
|
flexDirection: "column",
|
||||||
@ -98,19 +130,7 @@ function AddMapModal({
|
|||||||
<Label pt={2} pb={1}>
|
<Label pt={2} pb={1}>
|
||||||
Add map
|
Add map
|
||||||
</Label>
|
</Label>
|
||||||
<UIImage
|
<MapSelect maps={maps} onMapAdd={openImageDialog} />
|
||||||
my={2}
|
|
||||||
sx={{
|
|
||||||
width: "500px",
|
|
||||||
minHeight: "200px",
|
|
||||||
maxHeight: "300px",
|
|
||||||
objectFit: "contain",
|
|
||||||
borderRadius: "4px",
|
|
||||||
}}
|
|
||||||
src={mapSource}
|
|
||||||
onClick={openImageDialog}
|
|
||||||
bg="muted"
|
|
||||||
/>
|
|
||||||
<Flex>
|
<Flex>
|
||||||
<Box mb={2} mr={1} sx={{ flexGrow: 1 }}>
|
<Box mb={2} mr={1} sx={{ flexGrow: 1 }}>
|
||||||
<Label htmlFor="gridX">Columns</Label>
|
<Label htmlFor="gridX">Columns</Label>
|
||||||
@ -118,7 +138,7 @@ function AddMapModal({
|
|||||||
type="number"
|
type="number"
|
||||||
name="gridX"
|
name="gridX"
|
||||||
value={gridX}
|
value={gridX}
|
||||||
onChange={(e) => onGridXChange(e.target.value)}
|
onChange={(e) => setGridX(e.target.value)}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
<Box mb={2} ml={1} sx={{ flexGrow: 1 }}>
|
<Box mb={2} ml={1} sx={{ flexGrow: 1 }}>
|
||||||
@ -127,25 +147,13 @@ function AddMapModal({
|
|||||||
type="number"
|
type="number"
|
||||||
name="gridY"
|
name="gridY"
|
||||||
value={gridY}
|
value={gridY}
|
||||||
onChange={(e) => onGridYChange(e.target.value)}
|
onChange={(e) => setGridY(e.target.value)}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
</Flex>
|
</Flex>
|
||||||
{mapSource ? (
|
<Button variant="primary" disabled={imageLoading}>
|
||||||
<Button variant="primary" disabled={!imageLoaded}>
|
Done
|
||||||
Done
|
</Button>
|
||||||
</Button>
|
|
||||||
) : (
|
|
||||||
<Button
|
|
||||||
varient="primary"
|
|
||||||
onClick={(e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
openImageDialog();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Select Image
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
{dragging && (
|
{dragging && (
|
||||||
<Flex
|
<Flex
|
||||||
bg="muted"
|
bg="muted"
|
||||||
|
@ -1,10 +1,4 @@
|
|||||||
import React, {
|
import React, { useState, useEffect, useCallback, useContext } from "react";
|
||||||
useState,
|
|
||||||
useRef,
|
|
||||||
useEffect,
|
|
||||||
useCallback,
|
|
||||||
useContext,
|
|
||||||
} from "react";
|
|
||||||
import { Flex, Box, Text, Link } from "theme-ui";
|
import { Flex, Box, Text, Link } from "theme-ui";
|
||||||
import { useParams } from "react-router-dom";
|
import { useParams } from "react-router-dom";
|
||||||
|
|
||||||
@ -40,21 +34,19 @@ function Game() {
|
|||||||
* Map state
|
* Map state
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const [mapSource, setMapSource] = useState(null);
|
const [map, setMap] = useState(null);
|
||||||
const mapDataRef = useRef(null);
|
|
||||||
|
|
||||||
function handleMapChange(mapData, mapSource) {
|
function handleMapChange(newMap) {
|
||||||
mapDataRef.current = mapData;
|
setMap(newMap);
|
||||||
setMapSource(mapSource);
|
|
||||||
for (let peer of Object.values(peers)) {
|
for (let peer of Object.values(peers)) {
|
||||||
peer.connection.send({ id: "map", data: mapDataRef.current });
|
peer.connection.send({ id: "map", data: map });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const [mapTokens, setMapTokens] = useState({});
|
const [mapTokens, setMapTokens] = useState({});
|
||||||
|
|
||||||
function handleMapTokenChange(token) {
|
function handleMapTokenChange(token) {
|
||||||
if (!mapSource) {
|
if (!map.source) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setMapTokens((prevMapTokens) => ({
|
setMapTokens((prevMapTokens) => ({
|
||||||
@ -150,8 +142,8 @@ function Game() {
|
|||||||
|
|
||||||
function handlePeerData({ data, peer }) {
|
function handlePeerData({ data, peer }) {
|
||||||
if (data.id === "sync") {
|
if (data.id === "sync") {
|
||||||
if (mapSource) {
|
if (map) {
|
||||||
peer.connection.send({ id: "map", data: mapDataRef.current });
|
peer.connection.send({ id: "map", data: map });
|
||||||
}
|
}
|
||||||
if (mapTokens) {
|
if (mapTokens) {
|
||||||
peer.connection.send({ id: "tokenEdit", data: mapTokens });
|
peer.connection.send({ id: "tokenEdit", data: mapTokens });
|
||||||
@ -164,9 +156,9 @@ function Game() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (data.id === "map") {
|
if (data.id === "map") {
|
||||||
const blob = new Blob([data.data.file]);
|
const file = new Blob([data.data.file]);
|
||||||
mapDataRef.current = { ...data.data, file: blob };
|
const source = URL.createObjectURL(file);
|
||||||
setMapSource(URL.createObjectURL(mapDataRef.current.file));
|
setMap({ ...data.data, file, source });
|
||||||
}
|
}
|
||||||
if (data.id === "tokenEdit") {
|
if (data.id === "tokenEdit") {
|
||||||
setMapTokens((prevMapTokens) => ({
|
setMapTokens((prevMapTokens) => ({
|
||||||
@ -302,8 +294,7 @@ function Game() {
|
|||||||
onStreamEnd={handleStreamEnd}
|
onStreamEnd={handleStreamEnd}
|
||||||
/>
|
/>
|
||||||
<Map
|
<Map
|
||||||
mapSource={mapSource}
|
map={map}
|
||||||
mapData={mapDataRef.current}
|
|
||||||
tokens={mapTokens}
|
tokens={mapTokens}
|
||||||
onMapTokenChange={handleMapTokenChange}
|
onMapTokenChange={handleMapTokenChange}
|
||||||
onMapTokenRemove={handleMapTokenRemove}
|
onMapTokenRemove={handleMapTokenRemove}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user