import React, { useState, useRef } from "react"; import { Box, IconButton } from "theme-ui"; import { Stage, Layer, Image } from "react-konva"; import Konva from "konva"; import ReactResizeDetector from "react-resize-detector"; import useMapImage from "../../hooks/useMapImage"; import usePreventOverscroll from "../../hooks/usePreventOverscroll"; import useStageInteraction from "../../hooks/useStageInteraction"; import useImageCenter from "../../hooks/useImageCenter"; import useResponsiveLayout from "../../hooks/useResponsiveLayout"; import { getGridDefaultInset, getGridMaxZoom } from "../../helpers/grid"; import KonvaBridge from "../../helpers/KonvaBridge"; import { MapInteractionProvider } from "../../contexts/MapInteractionContext"; import { GridProvider } from "../../contexts/GridContext"; import ResetMapIcon from "../../icons/ResetMapIcon"; import GridOnIcon from "../../icons/GridOnIcon"; import GridOffIcon from "../../icons/GridOffIcon"; import MapGrid from "./MapGrid"; import MapGridEditor from "./MapGridEditor"; import { Map } from "../../types/Map"; import { GridInset } from "../../types/Grid"; import { MapSettingsChangeEventHandler } from "../../types/Events"; type MapEditorProps = { map: Map; onSettingsChange: MapSettingsChangeEventHandler; }; function MapEditor({ map, onSettingsChange }: MapEditorProps) { const [mapImage] = useMapImage(map); const [stageWidth, setStageWidth] = useState(1); const [stageHeight, setStageHeight] = useState(1); const [stageScale, setStageScale] = useState(1); const defaultInset = getGridDefaultInset(map.grid, map.width, map.height); const stageTranslateRef = useRef({ x: 0, y: 0 }); const mapStageRef = useRef(null); const mapLayerRef = useRef(null); const [preventMapInteraction, setPreventMapInteraction] = useState(false); function handleResize(width?: number, height?: number): void { if (width) { setStageWidth(width); } if (height) { setStageHeight(height); } } const containerRef = useRef(null); usePreventOverscroll(containerRef); const [mapWidth, mapHeight] = useImageCenter( map, mapStageRef, stageWidth, stageHeight, stageTranslateRef, setStageScale, mapLayerRef, containerRef, true ); useStageInteraction( mapStageRef, stageScale, setStageScale, stageTranslateRef, mapLayerRef, getGridMaxZoom(map.grid), "move", preventMapInteraction ); function handleGridChange(inset: GridInset) { onSettingsChange({ grid: { ...map.grid, inset, }, }); } function handleMapReset() { onSettingsChange({ grid: { ...map.grid, inset: defaultInset, }, }); } const [showGridControls, setShowGridControls] = useState(true); const mapInteraction = { stageScale, stageWidth, stageHeight, setPreventMapInteraction, mapWidth, mapHeight, interactionEmitter: null, }; const gridChanged = map.grid.inset.topLeft.x !== defaultInset.topLeft.x || map.grid.inset.topLeft.y !== defaultInset.topLeft.y || map.grid.inset.bottomRight.x !== defaultInset.bottomRight.x || map.grid.inset.bottomRight.y !== defaultInset.bottomRight.y; const gridValid = map.grid.size.x !== 0 && map.grid.size.y !== 0; const layout = useResponsiveLayout(); return ( ( {children} )} > {showGridControls && gridValid && ( <> )} {gridChanged && gridValid && ( )} setShowGridControls(!showGridControls)} bg="overlay" sx={{ borderRadius: "50%", position: "absolute", bottom: 0, right: 0, }} m={2} p="6px" > {showGridControls ? : } ); } export default MapEditor;