Added show map grid option to maps

This commit is contained in:
Mitchell McCaffrey 2020-05-31 16:25:05 +10:00
parent 0720a3df2b
commit faddf03ecf
6 changed files with 135 additions and 10 deletions

View File

@ -6,6 +6,7 @@ import MapToken from "./MapToken";
import MapDrawing from "./MapDrawing"; import MapDrawing from "./MapDrawing";
import MapFog from "./MapFog"; import MapFog from "./MapFog";
import MapDice from "./MapDice"; import MapDice from "./MapDice";
import MapGrid from "./MapGrid";
import TokenDataContext from "../../contexts/TokenDataContext"; import TokenDataContext from "../../contexts/TokenDataContext";
import MapLoadingContext from "../../contexts/MapLoadingContext"; import MapLoadingContext from "../../contexts/MapLoadingContext";
@ -294,6 +295,10 @@ function Map({
/> />
); );
const mapGrid = map && map.showGrid && (
<MapGrid map={map} gridSize={gridSizeNormalized} />
);
return ( return (
<MapInteraction <MapInteraction
map={map} map={map}
@ -308,6 +313,7 @@ function Map({
} }
selectedToolId={selectedToolId} selectedToolId={selectedToolId}
> >
{mapGrid}
{mapDrawing} {mapDrawing}
{mapTokens} {mapTokens}
{mapFog} {mapFog}

View File

@ -0,0 +1,93 @@
import React, { useContext, useEffect, useState } from "react";
import { Line, Group } from "react-konva";
import useImage from "use-image";
import MapInteractionContext from "../../contexts/MapInteractionContext";
import useDataSource from "../../helpers/useDataSource";
import { mapSources as defaultMapSources } from "../../maps";
import { getStrokeWidth } from "../../helpers/drawing";
const lightnessDetectionOffset = 0.1;
function MapGrid({ map, gridSize }) {
const mapSource = useDataSource(map, defaultMapSources);
const [mapImage, mapLoadingStatus] = useImage(mapSource);
const gridX = map && map.gridX;
const gridY = map && map.gridY;
const { mapWidth, mapHeight } = useContext(MapInteractionContext);
const lineSpacingX = mapWidth / gridX;
const lineSpacingY = mapHeight / gridY;
const [isImageLight, setIsImageLight] = useState(true);
// When the map changes find the average lightness of its pixels
useEffect(() => {
if (mapLoadingStatus === "loaded") {
const imageWidth = mapImage.width;
const imageHeight = mapImage.height;
let canvas = document.createElement("canvas");
canvas.width = imageWidth;
canvas.height = imageHeight;
let context = canvas.getContext("2d");
context.drawImage(mapImage, 0, 0);
const imageData = context.getImageData(0, 0, imageWidth, imageHeight);
const data = imageData.data;
let lightPixels = 0;
let darkPixels = 0;
// Loop over every pixels rgba values
for (let i = 0; i < data.length; i += 4) {
const r = data[i];
const g = data[i + 1];
const b = data[i + 2];
const max = Math.max(Math.max(r, g), b);
if (max < 128) {
darkPixels++;
} else {
lightPixels++;
}
}
const norm = (lightPixels - darkPixels) / (imageWidth * imageHeight);
if (norm + lightnessDetectionOffset < 0) {
setIsImageLight(false);
} else {
setIsImageLight(true);
}
}
}, [mapImage, mapLoadingStatus]);
const lines = [];
for (let x = 1; x < gridX; x++) {
lines.push(
<Line
key={`grid_x_${x}`}
points={[x * lineSpacingX, 0, x * lineSpacingX, mapHeight]}
stroke={isImageLight ? "black" : "white"}
strokeWidth={getStrokeWidth(0.1, gridSize, mapWidth, mapHeight)}
opacity={0.8}
/>
);
}
for (let y = 1; y < gridY; y++) {
lines.push(
<Line
key={`grid_y_${y}`}
points={[0, y * lineSpacingY, mapWidth, y * lineSpacingY]}
stroke={isImageLight ? "black" : "white"}
strokeWidth={getStrokeWidth(0.1, gridSize, mapWidth, mapHeight)}
opacity={0.8}
/>
);
}
return <Group>{lines}</Group>;
}
export default MapGrid;

View File

@ -3,6 +3,8 @@ import { Flex, Box, Label, Input, Checkbox, IconButton } from "theme-ui";
import ExpandMoreIcon from "../../icons/ExpandMoreIcon"; import ExpandMoreIcon from "../../icons/ExpandMoreIcon";
import Divider from "../Divider";
function MapSettings({ function MapSettings({
map, map,
mapState, mapState,
@ -57,6 +59,27 @@ function MapSettings({
{showMore && ( {showMore && (
<> <>
<Box mt={2} sx={{ flexGrow: 1 }}> <Box mt={2} sx={{ flexGrow: 1 }}>
<Label htmlFor="name">Name</Label>
<Input
name="name"
value={(map && map.name) || ""}
onChange={(e) => onSettingsChange("name", e.target.value)}
disabled={!map || map.type === "default"}
my={1}
/>
</Box>
<Box my={2}>
<Label>
<Checkbox
checked={map && map.showGrid}
disabled={!map || map.type === "default"}
onChange={(e) => onSettingsChange("showGrid", e.target.checked)}
/>
Show Grid
</Label>
</Box>
<Divider fill />
<Box my={2} sx={{ flexGrow: 1 }}>
<Label>Allow others to edit</Label> <Label>Allow others to edit</Label>
<Flex my={1}> <Flex my={1}>
<Label> <Label>
@ -85,16 +108,6 @@ function MapSettings({
</Label> </Label>
</Flex> </Flex>
</Box> </Box>
<Box my={2} sx={{ flexGrow: 1 }}>
<Label htmlFor="name">Name</Label>
<Input
name="name"
value={(map && map.name) || ""}
onChange={(e) => onSettingsChange("name", e.target.value)}
disabled={!map || map.type === "default"}
my={1}
/>
</Box>
</> </>
)} )}
<IconButton <IconButton

View File

@ -43,6 +43,7 @@ export function MapDataProvider({ children }) {
created: Date.now() + i, created: Date.now() + i,
lastModified: Date.now() + i, lastModified: Date.now() + i,
gridType: "grid", gridType: "grid",
showGrid: false,
}); });
// Add a state for the map if there isn't one already // Add a state for the map if there isn't one already
const state = await database.table("states").get(id); const state = await database.table("states").get(id);

View File

@ -89,6 +89,17 @@ function loadVersions(db) {
} }
}); });
}); });
// v1.3.1 - Added show grid option
db.version(4)
.stores({})
.upgrade((tx) => {
return tx
.table("maps")
.toCollection()
.modify((map) => {
map.showGrid = false;
});
});
} }
// Get the dexie database used in DatabaseContext // Get the dexie database used in DatabaseContext

View File

@ -17,6 +17,7 @@ const defaultMapProps = {
// Grid type // Grid type
// TODO: add support for hex horizontal and hex vertical // TODO: add support for hex horizontal and hex vertical
gridType: "grid", gridType: "grid",
showGrid: false,
}; };
function SelectMapModal({ function SelectMapModal({