'use client' import { useState, useEffect, useRef, useCallback } from 'react' import { AnchorPosition, TagPosition, DeviceData, RangeResult } from '@/lib/uwb-types' import DeviceConnection from './DeviceConnection' interface VisualizerProps { width?: number height?: number } export default function PositioningVisualizer({ width = 800, height = 600 }: VisualizerProps) { const canvasRef = useRef(null) const [anchors, setAnchors] = useState([]) const [tagPosition, setTagPosition] = useState(null) const [connectedDevices, setConnectedDevices] = useState([]) const [isConnected, setIsConnected] = useState(false) const [lastDataUpdate, setLastDataUpdate] = useState(0) // Mock data for development useEffect(() => { const mockAnchors: AnchorPosition[] = [ { anchorId: 0, x: 0, y: 0, confidence: 0.9, valid: true }, { anchorId: 1, x: 10, y: 0, confidence: 0.8, valid: true }, { anchorId: 2, x: 10, y: 8, confidence: 0.9, valid: true }, { anchorId: 3, x: 0, y: 8, confidence: 0.7, valid: true }, { anchorId: 4, x: 5, y: 4, confidence: 0.8, valid: true }, ] const mockTag: TagPosition = { x: 3.5, y: 2.1, timestamp: Date.now(), confidence: 0.85 } setAnchors(mockAnchors) setTagPosition(mockTag) }, []) // Canvas rendering useEffect(() => { const canvas = canvasRef.current if (!canvas) return const ctx = canvas.getContext('2d') if (!ctx) return // Clear canvas ctx.clearRect(0, 0, width, height) // Set up coordinate system (flip Y axis for standard cartesian) ctx.save() ctx.scale(1, -1) ctx.translate(0, -height) // Scale to fit data (assuming 12m x 10m warehouse area) const scale = Math.min(width / 12, height / 10) ctx.scale(scale, scale) ctx.translate(1, 1) // Small offset from edges // Draw grid ctx.strokeStyle = '#e5e7eb' ctx.lineWidth = 1 / scale for (let i = 0; i <= 12; i += 2) { ctx.beginPath() ctx.moveTo(i, 0) ctx.lineTo(i, 10) ctx.stroke() } for (let i = 0; i <= 10; i += 2) { ctx.beginPath() ctx.moveTo(0, i) ctx.lineTo(12, i) ctx.stroke() } // Draw anchors anchors.forEach(anchor => { if (!anchor.valid) return ctx.fillStyle = anchor.confidence > 0.8 ? '#10b981' : '#f59e0b' ctx.beginPath() ctx.arc(anchor.x, anchor.y, 0.3, 0, 2 * Math.PI) ctx.fill() // Anchor ID label ctx.save() ctx.scale(1, -1) // Flip text back ctx.fillStyle = '#374151' ctx.font = `${0.4}px Arial` ctx.textAlign = 'center' ctx.fillText( anchor.anchorId.toString(), anchor.x, -anchor.y + 0.15 ) ctx.restore() }) // Draw tag position if (tagPosition) { ctx.fillStyle = '#3b82f6' ctx.beginPath() ctx.arc(tagPosition.x, tagPosition.y, 0.2, 0, 2 * Math.PI) ctx.fill() // Tag confidence indicator ctx.strokeStyle = `rgba(59, 130, 246, ${tagPosition.confidence})` ctx.lineWidth = 3 / scale ctx.beginPath() ctx.arc(tagPosition.x, tagPosition.y, 0.5, 0, 2 * Math.PI) ctx.stroke() } ctx.restore() }, [anchors, tagPosition, width, height]) const connectToDevice = async () => { try { // This will be implemented with actual serial connection setIsConnected(true) console.log('Connecting to UWB device...') } catch (error) { console.error('Failed to connect:', error) } } // Handle real-time data updates const handleDataReceived = useCallback((data: any) => { setLastDataUpdate(Date.now()) if (data.rangeData) { // Process range data for positioning const rangeData: RangeResult = data.rangeData console.log('Range data received:', rangeData) // Update device data from range results const deviceUpdates: DeviceData[] = [] for (let i = 0; i < 8; i++) { if (rangeData.ranges[i] > 0 && rangeData.anchorIds[i] > 0) { deviceUpdates.push({ deviceId: rangeData.anchorIds[i], distance: rangeData.ranges[i], rssi: rangeData.rssi[i], lastUpdate: Date.now(), active: true }) } } setConnectedDevices(deviceUpdates) } }, []) const handleConnectionChange = useCallback((connected: boolean) => { setIsConnected(connected) if (!connected) { setConnectedDevices([]) setLastDataUpdate(0) } }, []) return (
{/* Device Connection */} {/* Status Panel */}

System Status

{/* Device Status */}
Active Anchors: {anchors.filter(a => a.valid).length}
Tag Position: {tagPosition ? `(${tagPosition.x.toFixed(1)}, ${tagPosition.y.toFixed(1)})` : 'No data' }
Confidence: {tagPosition ? `${(tagPosition.confidence * 100).toFixed(0)}%` : 'N/A' }
{/* Visualization Canvas */}

Warehouse Map

High Confidence Anchor
Low Confidence Anchor
Mobile Tag
) }