({
className = '',
onWaypointsChange,
activeMissionId,
onNavigationComplete,
initialWaypoints = [],
showNavPlan = false
}: MissionMapViewProps)
| 37 | } |
| 38 | |
| 39 | export default function MissionMapView({ |
| 40 | className = '', |
| 41 | onWaypointsChange, |
| 42 | activeMissionId, |
| 43 | onNavigationComplete, |
| 44 | initialWaypoints = [], |
| 45 | showNavPlan = false |
| 46 | }: MissionMapViewProps) { |
| 47 | const { connection } = useRobotConnection(); |
| 48 | const { t } = useLanguage(); |
| 49 | const { dispatch: notificationDispatch } = useNotifications(); |
| 50 | const canvasRef = useRef<HTMLCanvasElement>(null); |
| 51 | const containerRef = useRef<HTMLDivElement>(null); |
| 52 | const animationFrameRef = useRef<number | undefined>(undefined); |
| 53 | const mapTopic = '/map'; |
| 54 | const { occupancyGrid, isLoading, error, retry } = useOccupancyGrid({ topicName: mapTopic }); |
| 55 | |
| 56 | // Get robot position in map frame |
| 57 | const robotPose = useMapPose(); |
| 58 | |
| 59 | // Get navigation plan |
| 60 | const { navPlan } = useRosNavPlan('/plan'); |
| 61 | |
| 62 | // Local costmap for obstacle visualization |
| 63 | const [showLocalCostmap, setShowLocalCostmap] = useState(false); |
| 64 | const { occupancyGrid: localCostmap } = useOccupancyGrid({ |
| 65 | topicName: '/local_costmap/costmap', |
| 66 | enabled: showLocalCostmap, |
| 67 | throttleMs: 0 |
| 68 | }); |
| 69 | const localCostmapRef = useRef(localCostmap); |
| 70 | const costmapImageCacheRef = useRef<ImageData | null>(null); |
| 71 | const costmapDataHashRef = useRef<string>(''); |
| 72 | |
| 73 | // Nav2 FollowWaypoints action - proper waypoint following |
| 74 | const { |
| 75 | startNavigation: startFollowWaypoints, |
| 76 | cancelNavigation: cancelFollowWaypoints, |
| 77 | status: navigationStatus, |
| 78 | progress: navigationProgress, |
| 79 | error: navigationError, |
| 80 | isConnected: nav2Connected, |
| 81 | isActionServerAvailable, |
| 82 | } = useFollowWaypoints(); |
| 83 | |
| 84 | // Derived states for UI logic |
| 85 | // With the new FollowWaypoints action, Nav2 handles all sequencing server-side |
| 86 | // so we only need to check for 'navigating' status |
| 87 | const isNav2Navigating = navigationStatus === 'navigating'; |
| 88 | const nav2CurrentIndex = navigationProgress.currentWaypointIndex; |
| 89 | |
| 90 | // Waypoint management - Initialize with initialWaypoints |
| 91 | const [waypoints, setWaypoints] = useState<Waypoint[]>(initialWaypoints); |
| 92 | const [waypointReachedStatus, setWaypointReachedStatus] = useState<Record<string, boolean>>({}); |
| 93 | const [isEditMode, setIsEditMode] = useState(false); // Start in view mode by default |
| 94 | const [isDraggingWaypoint, setIsDraggingWaypoint] = useState<string | null>(null); |
| 95 | const [tempWaypoint, setTempWaypoint] = useState<Waypoint | null>(null); |
| 96 | const [selectedWaypointId, setSelectedWaypointId] = useState<string | null>(null); |
nothing calls this directly
no test coverage detected