Changed grid scale and offset to inset and added grid editor
This commit is contained in:
parent
539f216cfe
commit
3e5478f7a8
@ -330,9 +330,7 @@ function Map({
|
||||
/>
|
||||
);
|
||||
|
||||
const mapGrid = map && map.showGrid && (
|
||||
<MapGrid map={map} gridSize={gridSizeNormalized} />
|
||||
);
|
||||
const mapGrid = map && map.showGrid && <MapGrid map={map} />;
|
||||
|
||||
const mapMeasure = (
|
||||
<MapMeasure
|
||||
|
@ -7,7 +7,12 @@ import useMapImage from "../../helpers/useMapImage";
|
||||
import usePreventOverscroll from "../../helpers/usePreventOverscroll";
|
||||
import useStageInteraction from "../../helpers/useStageInteraction";
|
||||
|
||||
function MapEditor({ map }) {
|
||||
import { MapInteractionProvider } from "../../contexts/MapInteractionContext";
|
||||
|
||||
import MapGrid from "./MapGrid";
|
||||
import MapGridEditor from "./MapGridEditor";
|
||||
|
||||
function MapEditor({ map, onSettingsChange }) {
|
||||
const [mapImageSource] = useMapImage(map);
|
||||
|
||||
const [stageWidth, setStageWidth] = useState(1);
|
||||
@ -29,6 +34,7 @@ function MapEditor({ map }) {
|
||||
|
||||
const stageTranslateRef = useRef({ x: 0, y: 0 });
|
||||
const mapLayerRef = useRef();
|
||||
const [preventMapInteraction, setPreventMapInteraction] = useState(false);
|
||||
|
||||
function handleResize(width, height) {
|
||||
setStageWidth(width);
|
||||
@ -66,12 +72,30 @@ function MapEditor({ map }) {
|
||||
mapLayerRef.current,
|
||||
stageScale,
|
||||
setStageScale,
|
||||
stageTranslateRef
|
||||
stageTranslateRef,
|
||||
"pan",
|
||||
preventMapInteraction
|
||||
);
|
||||
|
||||
const containerRef = useRef();
|
||||
usePreventOverscroll(containerRef);
|
||||
|
||||
function handleGridChange(inset) {
|
||||
onSettingsChange("grid", {
|
||||
...map.grid,
|
||||
inset,
|
||||
});
|
||||
}
|
||||
|
||||
const mapInteraction = {
|
||||
stageScale,
|
||||
stageWidth,
|
||||
stageHeight,
|
||||
setPreventMapInteraction,
|
||||
mapWidth,
|
||||
mapHeight,
|
||||
};
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
@ -96,6 +120,10 @@ function MapEditor({ map }) {
|
||||
>
|
||||
<Layer ref={mapLayerRef}>
|
||||
<Image image={mapImageSource} width={mapWidth} height={mapHeight} />
|
||||
<MapInteractionProvider value={mapInteraction}>
|
||||
<MapGrid map={map} strokeWidth={0.5} />
|
||||
<MapGridEditor map={map} onGridChange={handleGridChange} />
|
||||
</MapInteractionProvider>
|
||||
</Layer>
|
||||
</Stage>
|
||||
</ReactResizeDetector>
|
||||
|
@ -10,7 +10,7 @@ import { mapSources as defaultMapSources } from "../../maps";
|
||||
import { getStrokeWidth } from "../../helpers/drawing";
|
||||
import { getImageLightness } from "../../helpers/image";
|
||||
|
||||
function MapGrid({ map, gridSize }) {
|
||||
function MapGrid({ map, strokeWidth }) {
|
||||
let mapSourceMap = map;
|
||||
// Use lowest resolution for grid lightness
|
||||
if (map && map.type === "file" && map.resolutions) {
|
||||
@ -24,6 +24,10 @@ function MapGrid({ map, gridSize }) {
|
||||
|
||||
const gridX = map && map.grid.size.x;
|
||||
const gridY = map && map.grid.size.y;
|
||||
const gridSizeNormalized = {
|
||||
x: gridX ? 1 / gridX : 0,
|
||||
y: gridY ? 1 / gridY : 0,
|
||||
};
|
||||
|
||||
const { mapWidth, mapHeight } = useContext(MapInteractionContext);
|
||||
|
||||
@ -35,6 +39,7 @@ function MapGrid({ map, gridSize }) {
|
||||
// When the map changes find the average lightness of its pixels
|
||||
useEffect(() => {
|
||||
if (mapLoadingStatus === "loaded") {
|
||||
console.log("getting lightness");
|
||||
setIsImageLight(getImageLightness(mapImage));
|
||||
}
|
||||
}, [mapImage, mapLoadingStatus]);
|
||||
@ -46,7 +51,12 @@ function MapGrid({ map, gridSize }) {
|
||||
key={`grid_x_${x}`}
|
||||
points={[x * lineSpacingX, 0, x * lineSpacingX, mapHeight]}
|
||||
stroke={isImageLight ? "black" : "white"}
|
||||
strokeWidth={getStrokeWidth(0.1, gridSize, mapWidth, mapHeight)}
|
||||
strokeWidth={getStrokeWidth(
|
||||
strokeWidth,
|
||||
gridSizeNormalized,
|
||||
mapWidth,
|
||||
mapHeight
|
||||
)}
|
||||
opacity={0.5}
|
||||
/>
|
||||
);
|
||||
@ -57,7 +67,12 @@ function MapGrid({ map, gridSize }) {
|
||||
key={`grid_y_${y}`}
|
||||
points={[0, y * lineSpacingY, mapWidth, y * lineSpacingY]}
|
||||
stroke={isImageLight ? "black" : "white"}
|
||||
strokeWidth={getStrokeWidth(0.1, gridSize, mapWidth, mapHeight)}
|
||||
strokeWidth={getStrokeWidth(
|
||||
strokeWidth,
|
||||
gridSizeNormalized,
|
||||
mapWidth,
|
||||
mapHeight
|
||||
)}
|
||||
opacity={0.5}
|
||||
/>
|
||||
);
|
||||
@ -66,4 +81,8 @@ function MapGrid({ map, gridSize }) {
|
||||
return <Group>{lines}</Group>;
|
||||
}
|
||||
|
||||
MapGrid.defaultProps = {
|
||||
strokeWidth: 0.1,
|
||||
};
|
||||
|
||||
export default MapGrid;
|
||||
|
156
src/components/map/MapGridEditor.js
Normal file
156
src/components/map/MapGridEditor.js
Normal file
@ -0,0 +1,156 @@
|
||||
import React, { useContext, useRef } from "react";
|
||||
import { Group, Circle, Rect } from "react-konva";
|
||||
|
||||
import MapInteractionContext from "../../contexts/MapInteractionContext";
|
||||
|
||||
import * as Vector2 from "../../helpers/vector2";
|
||||
|
||||
function MapGridEditor({ map, onGridChange }) {
|
||||
const {
|
||||
mapWidth,
|
||||
mapHeight,
|
||||
stageScale,
|
||||
setPreventMapInteraction,
|
||||
} = useContext(MapInteractionContext);
|
||||
|
||||
const mapSize = { x: mapWidth, y: mapHeight };
|
||||
|
||||
const topLeftHandleRef = useRef();
|
||||
const topRightHandleRef = useRef();
|
||||
const bottomRightHandleRef = useRef();
|
||||
const bottomLeftHandleRef = useRef();
|
||||
|
||||
function handleScaleCircleDragStart() {}
|
||||
|
||||
function handleScaleCircleDragMove(event) {
|
||||
onGridChange(getHandleInset(event.target));
|
||||
}
|
||||
|
||||
function handleScaleCircleDragEnd(event) {
|
||||
onGridChange(getHandleInset(event.target));
|
||||
setPreventMapInteraction(false);
|
||||
}
|
||||
|
||||
function handleInteractivePointerDown() {
|
||||
setPreventMapInteraction(true);
|
||||
}
|
||||
|
||||
function handleInteractivePointerUp() {
|
||||
setPreventMapInteraction(false);
|
||||
}
|
||||
|
||||
const editCircleRadius = Math.max(
|
||||
(Math.min(mapWidth, mapHeight) / 30) * Math.max(1 / stageScale, 1),
|
||||
1
|
||||
);
|
||||
|
||||
const editCircleProps = {
|
||||
radius: editCircleRadius,
|
||||
fill: "rgba(0, 0, 0, 0.5)",
|
||||
stroke: "white",
|
||||
strokeWidth: editCircleRadius / 5,
|
||||
draggable: true,
|
||||
onDragStart: handleScaleCircleDragStart,
|
||||
onDragMove: handleScaleCircleDragMove,
|
||||
onDragEnd: handleScaleCircleDragEnd,
|
||||
onMouseDown: handleInteractivePointerDown,
|
||||
onMouseUp: handleInteractivePointerUp,
|
||||
onTouchStart: handleInteractivePointerDown,
|
||||
onTouchEnd: handleInteractivePointerUp,
|
||||
};
|
||||
|
||||
const editRectProps = {
|
||||
fill: "transparent",
|
||||
stroke: "white",
|
||||
strokeWidth: editCircleRadius / 5,
|
||||
};
|
||||
|
||||
function getHandleInset(handle) {
|
||||
const topLeftHandle = topLeftHandleRef.current;
|
||||
const topRightHandle = topRightHandleRef.current;
|
||||
const bottomRightHandle = bottomRightHandleRef.current;
|
||||
const bottomLeftHandle = bottomLeftHandleRef.current;
|
||||
|
||||
const topLeft = Vector2.divide(
|
||||
{ x: topLeftHandle.x(), y: topLeftHandle.y() },
|
||||
mapSize
|
||||
);
|
||||
const topRight = Vector2.divide(
|
||||
{ x: topRightHandle.x(), y: topRightHandle.y() },
|
||||
mapSize
|
||||
);
|
||||
const bottomRight = Vector2.divide(
|
||||
{ x: bottomRightHandle.x(), y: bottomRightHandle.y() },
|
||||
mapSize
|
||||
);
|
||||
const bottomLeft = Vector2.divide(
|
||||
{ x: bottomLeftHandle.x(), y: bottomLeftHandle.y() },
|
||||
mapSize
|
||||
);
|
||||
|
||||
if (handle === topLeftHandle || handle === bottomRightHandle) {
|
||||
return { topLeft, bottomRight };
|
||||
} else {
|
||||
return {
|
||||
topLeft: { x: bottomLeft.x, y: topRight.y },
|
||||
bottomRight: { x: topRight.x, y: bottomLeft.y },
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function getHandlePositions() {
|
||||
const topLeft = Vector2.multiply(map.grid.inset.topLeft, mapSize);
|
||||
const bottomRight = Vector2.multiply(map.grid.inset.bottomRight, mapSize);
|
||||
|
||||
const size = Vector2.subtract(bottomRight, topLeft);
|
||||
const offset = Vector2.multiply(topLeft, -1);
|
||||
|
||||
return {
|
||||
topLeft,
|
||||
topRight: { x: bottomRight.x, y: topLeft.y },
|
||||
bottomRight,
|
||||
bottomLeft: { x: topLeft.x, y: bottomRight.y },
|
||||
size,
|
||||
offset,
|
||||
};
|
||||
}
|
||||
|
||||
const handlePositions = getHandlePositions();
|
||||
|
||||
return (
|
||||
<Group>
|
||||
<Rect
|
||||
width={handlePositions.size.x}
|
||||
height={handlePositions.size.y}
|
||||
offset={handlePositions.offset}
|
||||
{...editRectProps}
|
||||
/>
|
||||
<Circle
|
||||
ref={topLeftHandleRef}
|
||||
x={handlePositions.topLeft.x}
|
||||
y={handlePositions.topLeft.y}
|
||||
{...editCircleProps}
|
||||
/>
|
||||
<Circle
|
||||
ref={topRightHandleRef}
|
||||
x={handlePositions.topRight.x}
|
||||
y={handlePositions.topRight.y}
|
||||
{...editCircleProps}
|
||||
/>
|
||||
<Circle
|
||||
ref={bottomRightHandleRef}
|
||||
x={handlePositions.bottomRight.x}
|
||||
y={handlePositions.bottomRight.y}
|
||||
{...editCircleProps}
|
||||
/>
|
||||
<Circle
|
||||
ref={bottomLeftHandleRef}
|
||||
x={handlePositions.bottomLeft.x}
|
||||
y={handlePositions.bottomLeft.y}
|
||||
{...editCircleProps}
|
||||
/>
|
||||
</Group>
|
||||
);
|
||||
}
|
||||
|
||||
export default MapGridEditor;
|
@ -217,8 +217,7 @@ function loadVersions(db) {
|
||||
map.group = "";
|
||||
map.grid = {
|
||||
size: { x: map.gridX, y: map.gridY },
|
||||
scale: { x: 1, y: 1 },
|
||||
offset: { x: 0, y: 0 },
|
||||
inset: { topLeft: { x: 0, y: 0 }, bottomRight: { x: 1, y: 1 } },
|
||||
type: "square",
|
||||
};
|
||||
delete map.gridX;
|
||||
|
@ -23,8 +23,7 @@ export const maps = Object.keys(mapSources).map((key) => ({
|
||||
name: Case.capital(key),
|
||||
grid: {
|
||||
size: { x: 22, y: 22 },
|
||||
scale: { x: 1, y: 1 },
|
||||
offset: { x: 0, y: 0 },
|
||||
inset: { topLeft: { x: 0, y: 0 }, bottomRight: { x: 1, y: 1 } },
|
||||
type: "square",
|
||||
},
|
||||
width: 1024,
|
||||
|
@ -87,7 +87,10 @@ function EditMapModal({ isOpen, onDone, map, mapState }) {
|
||||
<Label pt={2} pb={1}>
|
||||
Edit map
|
||||
</Label>
|
||||
<MapEditor map={selectedMapWithChanges} />
|
||||
<MapEditor
|
||||
map={selectedMapWithChanges}
|
||||
onSettingsChange={handleMapSettingsChange}
|
||||
/>
|
||||
<MapSettings
|
||||
map={selectedMapWithChanges}
|
||||
mapState={selectedMapStateWithChanges}
|
||||
|
@ -167,8 +167,7 @@ function SelectMapModal({
|
||||
type: "file",
|
||||
grid: {
|
||||
size: { x: fileGridX, y: fileGridY },
|
||||
scale: { x: 1, y: 1 },
|
||||
offset: { x: 0, y: 0 },
|
||||
inset: { topLeft: { x: 0, y: 0 }, bottomRight: { x: 1, y: 1 } },
|
||||
type: "square",
|
||||
},
|
||||
width: image.width,
|
||||
|
Loading…
x
Reference in New Issue
Block a user