import React, { useState, useRef, useEffect } from "react"; import { Box, IconButton } from "theme-ui"; import { Stage, Layer, Image } from "react-konva"; import ReactResizeDetector from "react-resize-detector"; import useMapImage from "../../helpers/useMapImage"; import usePreventOverscroll from "../../helpers/usePreventOverscroll"; import useStageInteraction from "../../helpers/useStageInteraction"; import { getMapDefaultInset } from "../../helpers/map"; import { MapInteractionProvider } from "../../contexts/MapInteractionContext"; import ResetMapIcon from "../../icons/ResetMapIcon"; import GridOnIcon from "../../icons/GridOnIcon"; import GridOffIcon from "../../icons/GridOffIcon"; import MapGrid from "./MapGrid"; import MapGridEditor from "./MapGridEditor"; function MapEditor({ map, onSettingsChange }) { const [mapImageSource] = useMapImage(map); const [stageWidth, setStageWidth] = useState(1); const [stageHeight, setStageHeight] = useState(1); const [stageScale, setStageScale] = useState(1); const stageRatio = stageWidth / stageHeight; const mapRatio = map ? map.width / map.height : 1; let mapWidth; let mapHeight; if (stageRatio > mapRatio) { mapWidth = map ? stageHeight / (map.height / map.width) : stageWidth; mapHeight = stageHeight; } else { mapWidth = stageWidth; mapHeight = map ? stageWidth * (map.height / map.width) : stageHeight; } const defaultInset = getMapDefaultInset( map.width, map.height, map.grid.size.x, map.grid.size.y ); const stageTranslateRef = useRef({ x: 0, y: 0 }); const mapLayerRef = useRef(); const [preventMapInteraction, setPreventMapInteraction] = useState(false); function handleResize(width, height) { setStageWidth(width); setStageHeight(height); } // Reset map translate and scale useEffect(() => { const layer = mapLayerRef.current; const containerRect = containerRef.current.getBoundingClientRect(); if (layer) { let newTranslate; if (stageRatio > mapRatio) { newTranslate = { x: -(mapWidth - containerRect.width) / 2, y: 0, }; } else { newTranslate = { x: 0, y: -(mapHeight - containerRect.height) / 2, }; } layer.x(newTranslate.x); layer.y(newTranslate.y); layer.draw(); stageTranslateRef.current = newTranslate; setStageScale(1); } }, [map.id, mapWidth, mapHeight, stageRatio, mapRatio]); const bind = useStageInteraction( mapLayerRef.current, stageScale, setStageScale, stageTranslateRef, "pan", preventMapInteraction ); const containerRef = useRef(); usePreventOverscroll(containerRef); function handleGridChange(inset) { 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, }; const canEditGrid = map.type !== "default"; 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; return ( {showGridControls && canEditGrid && ( )} {showGridControls && canEditGrid && ( )} {gridChanged && ( )} {canEditGrid && ( setShowGridControls(!showGridControls)} bg="overlay" sx={{ borderRadius: "50%", position: "absolute", bottom: 0, right: 0, }} m={2} p="6px" > {showGridControls ? : } )} ); } export default MapEditor;