Added multiple map layout and basic data flow
This commit is contained in:
@@ -1,11 +1,9 @@
|
||||
import React, { useRef, useState, useEffect } from "react";
|
||||
import React, { useState } from "react";
|
||||
import { IconButton } from "theme-ui";
|
||||
|
||||
import AddMapModal from "../../modals/AddMapModal";
|
||||
import AddMapIcon from "../../icons/AddMapIcon";
|
||||
|
||||
const defaultMapSize = 22;
|
||||
|
||||
function AddMapButton({ onMapChange }) {
|
||||
const [isAddModalOpen, setIsAddModalOpen] = useState(false);
|
||||
function openModal() {
|
||||
@@ -15,49 +13,11 @@ function AddMapButton({ onMapChange }) {
|
||||
setIsAddModalOpen(false);
|
||||
}
|
||||
|
||||
const [imageLoaded, setImageLoaded] = useState(false);
|
||||
|
||||
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);
|
||||
}
|
||||
function handleDone(map) {
|
||||
onMapChange(map);
|
||||
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 (
|
||||
<>
|
||||
<IconButton aria-label="Add Map" title="Add Map" onClick={openModal}>
|
||||
@@ -67,13 +27,6 @@ function AddMapButton({ onMapChange }) {
|
||||
isOpen={isAddModalOpen}
|
||||
onRequestClose={closeModal}
|
||||
onDone={handleDone}
|
||||
onImageUpload={handleImageUpload}
|
||||
gridX={gridX}
|
||||
onGridXChange={setGridX}
|
||||
gridY={gridY}
|
||||
onGridYChange={setGridY}
|
||||
imageLoaded={imageLoaded}
|
||||
mapSource={mapSource}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
||||
+11
-12
@@ -17,8 +17,7 @@ const minZoom = 0.1;
|
||||
const maxZoom = 5;
|
||||
|
||||
function Map({
|
||||
mapSource,
|
||||
mapData,
|
||||
map,
|
||||
tokens,
|
||||
onMapTokenChange,
|
||||
onMapTokenRemove,
|
||||
@@ -80,7 +79,7 @@ function Map({
|
||||
}, [drawActions, drawActionIndex]);
|
||||
|
||||
const disabledTools = [];
|
||||
if (!mapData) {
|
||||
if (!map) {
|
||||
disabledTools.push("pan");
|
||||
disabledTools.push("brush");
|
||||
}
|
||||
@@ -134,7 +133,7 @@ function Map({
|
||||
move: (e) => handleMove(e, false),
|
||||
},
|
||||
cursorChecker: () => {
|
||||
return selectedTool === "pan" && mapData ? "move" : "default";
|
||||
return selectedTool === "pan" && map ? "move" : "default";
|
||||
},
|
||||
})
|
||||
.on("doubletap", (event) => {
|
||||
@@ -147,12 +146,12 @@ function Map({
|
||||
return () => {
|
||||
mapInteract.unset();
|
||||
};
|
||||
}, [selectedTool, mapData]);
|
||||
}, [selectedTool, map]);
|
||||
|
||||
// Reset map transform when map changes
|
||||
useEffect(() => {
|
||||
setTranslateAndScale({ x: 0, y: 0 }, 1);
|
||||
}, [mapSource]);
|
||||
}, [map]);
|
||||
|
||||
// Bind the wheel event of the map via a ref
|
||||
// in order to support non-passive event listening
|
||||
@@ -194,11 +193,11 @@ function Map({
|
||||
|
||||
const mapRef = useRef(null);
|
||||
const mapContainerRef = useRef();
|
||||
const gridX = mapData && mapData.gridX;
|
||||
const gridY = mapData && mapData.gridY;
|
||||
const gridX = map && map.gridX;
|
||||
const gridY = map && map.gridY;
|
||||
const gridSizeNormalized = { x: 1 / gridX || 0, y: 1 / gridY || 0 };
|
||||
const tokenSizePercent = gridSizeNormalized.x * 100;
|
||||
const aspectRatio = (mapData && mapData.width / mapData.height) || 1;
|
||||
const aspectRatio = (map && map.width / map.height) || 1;
|
||||
|
||||
const mapImage = (
|
||||
<Box
|
||||
@@ -218,7 +217,7 @@ function Map({
|
||||
userSelect: "none",
|
||||
touchAction: "none",
|
||||
}}
|
||||
src={mapSource}
|
||||
src={map && map.source}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
@@ -278,8 +277,8 @@ function Map({
|
||||
/>
|
||||
{mapImage}
|
||||
<MapDrawing
|
||||
width={mapData ? mapData.width : 0}
|
||||
height={mapData ? mapData.height : 0}
|
||||
width={map ? map.width : 0}
|
||||
height={map ? map.height : 0}
|
||||
selectedTool={selectedTool}
|
||||
shapes={drawnShapes}
|
||||
onShapeAdd={handleShapeAdd}
|
||||
|
||||
@@ -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;
|
||||
Reference in New Issue
Block a user