import React, { useState, useEffect } from "react"; import { Group, Line, Text, Label, Tag } from "react-konva"; import { useDebouncedStageScale, useMapWidth, useMapHeight, useInteractionEmitter, } from "../../contexts/MapInteractionContext"; import { useMapStage } from "../../contexts/MapStageContext"; import { useGrid, useGridCellPixelSize, useGridCellNormalizedSize, useGridStrokeWidth, useGridOffset, } from "../../contexts/GridContext"; import { getDefaultShapeData, getUpdatedShapeData, } from "../../helpers/drawing"; import Vector2 from "../../helpers/Vector2"; import { getRelativePointerPosition } from "../../helpers/konva"; import { parseGridScale, gridDistance } from "../../helpers/grid"; import useGridSnapping from "../../hooks/useGridSnapping"; function MapMeasure({ map, active }) { const stageScale = useDebouncedStageScale(); const mapWidth = useMapWidth(); const mapHeight = useMapHeight(); const interactionEmitter = useInteractionEmitter(); const grid = useGrid(); const gridCellNormalizedSize = useGridCellNormalizedSize(); const gridCellPixelSize = useGridCellPixelSize(); const gridStrokeWidth = useGridStrokeWidth(); const gridOffset = useGridOffset(); const mapStageRef = useMapStage(); const [drawingShapeData, setDrawingShapeData] = useState(null); const [isBrushDown, setIsBrushDown] = useState(false); const gridScale = parseGridScale(active && grid.measurement.scale); const snapPositionToGrid = useGridSnapping(); useEffect(() => { if (!active) { return; } const mapStage = mapStageRef.current; const mapImage = mapStage?.findOne("#mapImage"); function getBrushPosition() { const mapImage = mapStage.findOne("#mapImage"); let position = getRelativePointerPosition(mapImage); if (map.snapToGrid) { position = snapPositionToGrid(position); } return Vector2.divide(position, { x: mapImage.width(), y: mapImage.height(), }); } function handleBrushDown() { const brushPosition = getBrushPosition(); const { points } = getDefaultShapeData("line", brushPosition); const length = 0; setDrawingShapeData({ length, points }); setIsBrushDown(true); } function handleBrushMove() { const brushPosition = getBrushPosition(); if (isBrushDown && drawingShapeData) { const { points } = getUpdatedShapeData( "line", drawingShapeData, brushPosition, gridCellNormalizedSize ); // Convert back to pixel values const a = Vector2.subtract( Vector2.multiply(points[0], { x: mapImage.width(), y: mapImage.height(), }), gridOffset ); const b = Vector2.subtract( Vector2.multiply(points[1], { x: mapImage.width(), y: mapImage.height(), }), gridOffset ); const length = gridDistance(grid, a, b, gridCellPixelSize); setDrawingShapeData({ length, points, }); } } function handleBrushUp() { setDrawingShapeData(null); setIsBrushDown(false); } interactionEmitter.on("dragStart", handleBrushDown); interactionEmitter.on("drag", handleBrushMove); interactionEmitter.on("dragEnd", handleBrushUp); return () => { interactionEmitter.off("dragStart", handleBrushDown); interactionEmitter.off("drag", handleBrushMove); interactionEmitter.off("dragEnd", handleBrushUp); }; }); function renderShape(shapeData) { const linePoints = shapeData.points.reduce( (acc, point) => [...acc, point.x * mapWidth, point.y * mapHeight], [] ); const lineCenter = Vector2.multiply( Vector2.divide(Vector2.add(shapeData.points[0], shapeData.points[1]), 2), { x: mapWidth, y: mapHeight } ); return ( ); } return {drawingShapeData && renderShape(drawingShapeData)}; } export default MapMeasure;