@@ -319,6 +319,13 @@ export class WarehouseBlueprintEditor extends Component {
319319
320320 // Coordinate export
321321 coordinateFormat : 'json' , // json, csv, geojson
322+
323+ // Cursor tracking and coordinate picking
324+ cursorPosition : { x : 0 , y : 0 } ,
325+ showCursor : true ,
326+ pickCoordinatesMode : false ,
327+ pickedPoints : [ ] , // Array of {x, y, label} for marked points
328+ pickingStep : 'start' , // 'start' or 'end'
322329 } ) ;
323330
324331 // Canvas context
@@ -901,7 +908,17 @@ export class WarehouseBlueprintEditor extends Component {
901908 this . drawDragPreview ( ctx ) ;
902909 }
903910
911+ // Draw picked coordinate points
912+ if ( this . state . pickedPoints . length > 0 ) {
913+ this . drawPickedPoints ( ctx ) ;
914+ }
915+
904916 ctx . restore ( ) ;
917+
918+ // Draw cursor position indicator (outside transform for screen coordinates)
919+ if ( this . state . showCursor ) {
920+ this . drawCursorInfo ( this . overlayCtx ) ;
921+ }
905922 }
906923
907924 drawNavigationPath ( ctx ) {
@@ -1031,6 +1048,12 @@ export class WarehouseBlueprintEditor extends Component {
10311048 onMouseDown ( ev ) {
10321049 const pos = this . getMousePosition ( ev ) ;
10331050
1051+ // Handle coordinate picking mode
1052+ if ( this . state . pickCoordinatesMode ) {
1053+ this . handleCoordinatePick ( pos ) ;
1054+ return ;
1055+ }
1056+
10341057 if ( this . state . navigationMode ) {
10351058 this . handleNavigationClick ( pos ) ;
10361059 return ;
@@ -1046,10 +1069,20 @@ export class WarehouseBlueprintEditor extends Component {
10461069 onMouseMove ( ev ) {
10471070 const pos = this . getMousePosition ( ev ) ;
10481071
1072+ // Always update cursor position for coordinate display
1073+ this . state . cursorPosition = {
1074+ x : Math . round ( pos . x ) ,
1075+ y : Math . round ( pos . y ) ,
1076+ xFeet : Math . round ( pos . x / 12 * 10 ) / 10 ,
1077+ yFeet : Math . round ( pos . y / 12 * 10 ) / 10
1078+ } ;
1079+
10491080 if ( this . state . isDragging ) {
10501081 this . state . dragCurrent = pos ;
1051- this . renderOverlay ( ) ;
10521082 }
1083+
1084+ // Always re-render overlay to show cursor position
1085+ this . renderOverlay ( ) ;
10531086 }
10541087
10551088 onMouseUp ( ev ) {
@@ -1290,9 +1323,205 @@ export class WarehouseBlueprintEditor extends Component {
12901323 this . state . navigationMode = false ;
12911324 this . state . navigationStart = null ;
12921325 this . state . navigationEnd = null ;
1326+ this . state . pickCoordinatesMode = false ;
1327+ this . state . pickingStep = 'start' ;
1328+ this . renderOverlay ( ) ;
1329+ }
1330+
1331+ clearPickedPoints ( ) {
1332+ this . state . pickedPoints = [ ] ;
1333+ this . state . pickingStep = 'start' ;
1334+ this . renderOverlay ( ) ;
1335+ }
1336+
1337+ togglePickCoordinatesMode ( ) {
1338+ this . state . pickCoordinatesMode = ! this . state . pickCoordinatesMode ;
1339+ if ( this . state . pickCoordinatesMode ) {
1340+ this . state . mode = 'select' ;
1341+ this . state . pickedPoints = [ ] ;
1342+ this . state . pickingStep = 'start' ;
1343+ this . notification . add ( "Click to mark START point, then END point for wall coordinates" , { type : "info" } ) ;
1344+ } else {
1345+ this . notification . add ( "Coordinate picking disabled" , { type : "info" } ) ;
1346+ }
1347+ this . renderOverlay ( ) ;
1348+ }
1349+
1350+ handleCoordinatePick ( pos ) {
1351+ const point = {
1352+ x : Math . round ( pos . x ) ,
1353+ y : Math . round ( pos . y ) ,
1354+ xFeet : Math . round ( pos . x / 12 * 10 ) / 10 ,
1355+ yFeet : Math . round ( pos . y / 12 * 10 ) / 10 ,
1356+ label : this . state . pickingStep === 'start' ? 'START' : 'END'
1357+ } ;
1358+
1359+ if ( this . state . pickingStep === 'start' ) {
1360+ // Clear previous points and add start
1361+ this . state . pickedPoints = [ point ] ;
1362+ this . state . pickingStep = 'end' ;
1363+ this . notification . add ( `START: X=${ point . x } " (${ point . xFeet } ft), Y=${ point . y } " (${ point . yFeet } ft) - Now click END point` , { type : "success" } ) ;
1364+ } else {
1365+ // Add end point
1366+ this . state . pickedPoints . push ( point ) ;
1367+ this . state . pickingStep = 'start' ;
1368+
1369+ const start = this . state . pickedPoints [ 0 ] ;
1370+ const end = point ;
1371+
1372+ // Show complete wall coordinates
1373+ this . notification . add (
1374+ `Wall coordinates: Start(${ start . x } , ${ start . y } ) → End(${ end . x } , ${ end . y } ) | ` +
1375+ `In feet: Start(${ start . xFeet } , ${ start . yFeet } ) → End(${ end . xFeet } , ${ end . yFeet } )` ,
1376+ { type : "success" , sticky : true }
1377+ ) ;
1378+ }
1379+
12931380 this . renderOverlay ( ) ;
12941381 }
12951382
1383+ drawPickedPoints ( ctx ) {
1384+ const scale = this . getScale ( ) ;
1385+
1386+ for ( let i = 0 ; i < this . state . pickedPoints . length ; i ++ ) {
1387+ const point = this . state . pickedPoints [ i ] ;
1388+ const x = point . x * scale ;
1389+ const y = point . y * scale ;
1390+
1391+ // Draw marker circle
1392+ ctx . beginPath ( ) ;
1393+ ctx . arc ( x , y , 12 , 0 , Math . PI * 2 ) ;
1394+ ctx . fillStyle = point . label === 'START' ? '#4CAF50' : '#F44336' ;
1395+ ctx . fill ( ) ;
1396+ ctx . strokeStyle = '#FFFFFF' ;
1397+ ctx . lineWidth = 2 ;
1398+ ctx . stroke ( ) ;
1399+
1400+ // Draw label
1401+ ctx . fillStyle = '#FFFFFF' ;
1402+ ctx . font = 'bold 10px Arial' ;
1403+ ctx . textAlign = 'center' ;
1404+ ctx . textBaseline = 'middle' ;
1405+ ctx . fillText ( point . label === 'START' ? 'S' : 'E' , x , y ) ;
1406+
1407+ // Draw coordinate box
1408+ ctx . fillStyle = 'rgba(0, 0, 0, 0.8)' ;
1409+ const coordText = `${ point . x } ", ${ point . y } " (${ point . xFeet } ft, ${ point . yFeet } ft)` ;
1410+ const textWidth = ctx . measureText ( coordText ) . width + 10 ;
1411+ const boxY = point . label === 'START' ? y - 35 : y + 20 ;
1412+
1413+ ctx . fillRect ( x - textWidth / 2 , boxY , textWidth , 18 ) ;
1414+ ctx . fillStyle = '#FFFFFF' ;
1415+ ctx . font = '11px Arial' ;
1416+ ctx . fillText ( coordText , x , boxY + 10 ) ;
1417+
1418+ // Draw line between points if we have both
1419+ if ( i === 1 && this . state . pickedPoints . length === 2 ) {
1420+ const start = this . state . pickedPoints [ 0 ] ;
1421+ ctx . beginPath ( ) ;
1422+ ctx . moveTo ( start . x * scale , start . y * scale ) ;
1423+ ctx . lineTo ( x , y ) ;
1424+ ctx . strokeStyle = '#2196F3' ;
1425+ ctx . lineWidth = 3 ;
1426+ ctx . setLineDash ( [ 8 , 4 ] ) ;
1427+ ctx . stroke ( ) ;
1428+ ctx . setLineDash ( [ ] ) ;
1429+
1430+ // Draw length label
1431+ const dx = point . x - start . x ;
1432+ const dy = point . y - start . y ;
1433+ const length = Math . sqrt ( dx * dx + dy * dy ) ;
1434+ const midX = ( start . x * scale + x ) / 2 ;
1435+ const midY = ( start . y * scale + y ) / 2 ;
1436+
1437+ ctx . fillStyle = 'rgba(33, 150, 243, 0.9)' ;
1438+ const lengthText = `Length: ${ Math . round ( length ) } " (${ Math . round ( length / 12 * 10 ) / 10 } ft)` ;
1439+ const lengthWidth = ctx . measureText ( lengthText ) . width + 10 ;
1440+ ctx . fillRect ( midX - lengthWidth / 2 , midY - 10 , lengthWidth , 20 ) ;
1441+ ctx . fillStyle = '#FFFFFF' ;
1442+ ctx . font = 'bold 11px Arial' ;
1443+ ctx . fillText ( lengthText , midX , midY + 4 ) ;
1444+ }
1445+ }
1446+ }
1447+
1448+ drawCursorInfo ( ctx ) {
1449+ const canvas = this . overlayCanvasRef . el ;
1450+ const pos = this . state . cursorPosition ;
1451+
1452+ // Only show if cursor is within blueprint bounds
1453+ if ( ! this . state . blueprint || pos . x < 0 || pos . y < 0 ||
1454+ pos . x > this . state . blueprint . length || pos . y > this . state . blueprint . width ) {
1455+ return ;
1456+ }
1457+
1458+ // Draw cursor crosshair on the canvas (in transformed space)
1459+ const scale = this . getScale ( ) ;
1460+ const screenX = pos . x * scale * this . state . zoom + this . state . panX ;
1461+ const screenY = pos . y * scale * this . state . zoom + this . state . panY ;
1462+
1463+ // Crosshair lines
1464+ ctx . strokeStyle = 'rgba(33, 150, 243, 0.5)' ;
1465+ ctx . lineWidth = 1 ;
1466+ ctx . setLineDash ( [ 5 , 5 ] ) ;
1467+
1468+ // Vertical line
1469+ ctx . beginPath ( ) ;
1470+ ctx . moveTo ( screenX , 0 ) ;
1471+ ctx . lineTo ( screenX , canvas . height ) ;
1472+ ctx . stroke ( ) ;
1473+
1474+ // Horizontal line
1475+ ctx . beginPath ( ) ;
1476+ ctx . moveTo ( 0 , screenY ) ;
1477+ ctx . lineTo ( canvas . width , screenY ) ;
1478+ ctx . stroke ( ) ;
1479+
1480+ ctx . setLineDash ( [ ] ) ;
1481+
1482+ // Coordinate display box (bottom-right corner)
1483+ const boxWidth = 200 ;
1484+ const boxHeight = this . state . pickCoordinatesMode ? 80 : 60 ;
1485+ const boxX = canvas . width - boxWidth - 10 ;
1486+ const boxY = canvas . height - boxHeight - 10 ;
1487+
1488+ ctx . fillStyle = 'rgba(0, 0, 0, 0.85)' ;
1489+ ctx . fillRect ( boxX , boxY , boxWidth , boxHeight ) ;
1490+
1491+ ctx . fillStyle = '#FFFFFF' ;
1492+ ctx . font = '12px monospace' ;
1493+ ctx . textAlign = 'left' ;
1494+
1495+ // Title
1496+ ctx . font = 'bold 11px Arial' ;
1497+ ctx . fillText ( '📍 Cursor Position' , boxX + 10 , boxY + 16 ) ;
1498+
1499+ // Coordinates
1500+ ctx . font = '12px monospace' ;
1501+ ctx . fillText ( `X: ${ pos . x } " (${ pos . xFeet } ft)` , boxX + 10 , boxY + 34 ) ;
1502+ ctx . fillText ( `Y: ${ pos . y } " (${ pos . yFeet } ft)` , boxX + 10 , boxY + 50 ) ;
1503+
1504+ // Pick mode indicator
1505+ if ( this . state . pickCoordinatesMode ) {
1506+ ctx . fillStyle = this . state . pickingStep === 'start' ? '#4CAF50' : '#F44336' ;
1507+ ctx . fillText ( `Click: ${ this . state . pickingStep . toUpperCase ( ) } point` , boxX + 10 , boxY + 68 ) ;
1508+ }
1509+
1510+ // Axis labels on the edges
1511+ ctx . fillStyle = 'rgba(0, 0, 0, 0.7)' ;
1512+ ctx . fillRect ( screenX - 25 , 5 , 50 , 18 ) ;
1513+ ctx . fillStyle = '#FFFFFF' ;
1514+ ctx . font = '10px monospace' ;
1515+ ctx . textAlign = 'center' ;
1516+ ctx . fillText ( `${ pos . x } "` , screenX , 17 ) ;
1517+
1518+ ctx . fillStyle = 'rgba(0, 0, 0, 0.7)' ;
1519+ ctx . fillRect ( 5 , screenY - 9 , 50 , 18 ) ;
1520+ ctx . fillStyle = '#FFFFFF' ;
1521+ ctx . textAlign = 'left' ;
1522+ ctx . fillText ( `${ pos . y } "` , 10 , screenY + 5 ) ;
1523+ }
1524+
12961525 deleteSelectedElement ( ) {
12971526 // TODO: Implement delete selected element
12981527 this . notification . add ( "Delete not yet implemented" , { type : "warning" } ) ;
0 commit comments