diff --git a/RobotApp.Client/Pages/Components/Monitor/RobotMonitorView.razor b/RobotApp.Client/Pages/Components/Monitor/RobotMonitorView.razor
index ace1b8b..501eb37 100644
--- a/RobotApp.Client/Pages/Components/Monitor/RobotMonitorView.razor
+++ b/RobotApp.Client/Pages/Components/Monitor/RobotMonitorView.razor
@@ -22,7 +22,14 @@
{
- X: @MonitorData.RobotPosition.X.ToString("F2")m | Y: @MonitorData.RobotPosition.Y.ToString("F2")m | θ: @((MonitorData.RobotPosition.Theta * 180 / Math.PI).ToString("F1"))°
+ Robot: X: @MonitorData.RobotPosition.X.ToString("F2")m | Y: @MonitorData.RobotPosition.Y.ToString("F2")m | θ: @((MonitorData.RobotPosition.Theta * 180 / Math.PI).ToString("F1"))°
+
+ }
+ @if (MouseWorldX.HasValue && MouseWorldY.HasValue)
+ {
+
+
+ Mouse: X: @MouseWorldX.Value.ToString("F2")m | Y: @MouseWorldY.Value.ToString("F2")m
}
@*
@@ -36,18 +43,49 @@
@onmousemove="HandleMouseMove"
@onmouseup="HandleMouseUp"
@onmouseleave="HandleMouseLeave">
+ @* Arrow markers for origin *@
+
+
+
+
+
+
+
+
+ @* Background Map Image *@
+ @if (MapImageLoaded && MapImageWidth > 0 && MapImageHeight > 0)
+ {
+
+ }
+
+ @* Origin Marker (2 arrows: X+ and Y+) *@
+
+ @* X+ Arrow (pointing right) *@
+
+ @* Y+ Arrow (pointing up in world, down in SVG) *@
+
+ @* Origin point *@
+
+
+
@if (MonitorData?.HasOrder == true)
{
- @* @for (int i = 0; i < MonitorData.EdgeStates.Length; i++)
- {
- var edge = MonitorData.EdgeStates[i];
- var (startX, startY, endX, endY) = GetEdgeEndpoints(i, edge);
-
- } *@
("getElementSize", SvgContainerRef);
+ var containerSize = await JS.InvokeAsync("robotMonitor.getElementSize", SvgContainerRef);
SvgWidth = containerSize.Width;
SvgHeight = containerSize.Height;
+ // Load map image and get dimensions
+ await LoadMapImage();
+
// Center view on robot if available with initial zoom
if (MonitorData?.RobotPosition != null)
{
@@ -150,6 +205,31 @@
}
}
+ private async Task LoadMapImage()
+ {
+ try
+ {
+ var imageDimensions = await JS.InvokeAsync("robotMonitor.loadImageAndGetDimensions", MapImageUrl);
+
+ // Convert pixel dimensions to world coordinates (meters)
+ MapImageWidth = imageDimensions.Width * MapImageResolution;
+ MapImageHeight = imageDimensions.Height * MapImageResolution;
+
+ Console.WriteLine($"Map image loaded: {imageDimensions.Width}x{imageDimensions.Height} pixels, {MapImageWidth}x{MapImageHeight} meters");
+
+ if (MapImageWidth > 0 && MapImageHeight > 0)
+ {
+ MapImageLoaded = true;
+ await InvokeAsync(StateHasChanged); // Force re-render after image is loaded
+ }
+ }
+ catch (Exception ex)
+ {
+ MapImageLoaded = false;
+ Console.WriteLine($"Failed to load map image: {ex.Message}");
+ }
+ }
+
private string GetTransform()
{
return $"translate({TranslateX}, {TranslateY}) scale({ZoomScale * BASE_PIXELS_PER_METER})";
@@ -217,6 +297,31 @@
return -worldY;
}
+ private string GetOriginMarkerTransform()
+ {
+ // Origin is at (MapImageOriginX, MapImageOriginY) in world coordinates
+ // In SVG: (MapImageOriginX, -MapImageOriginY)
+ var x = WorldToSvgX(MapImageOriginX);
+ var y = WorldToSvgY(MapImageOriginY);
+ return $"translate({x}, {y})";
+ }
+
+ private double GetOriginMarkerSize()
+ {
+ // Marker size in world coordinates (meters)
+ const double BaseMarkerSize = 0.5; // 1 meter
+ double scaleFactor = 1.0 / ZoomScale; // Keep visual size constant
+ return BaseMarkerSize * scaleFactor;
+ }
+
+ private double GetOriginMarkerStrokeWidth()
+ {
+ // Stroke width in world coordinates
+ const double BaseStrokeWidth = 0.05; // 5cm
+ double scaleFactor = 1.0 / ZoomScale; // Keep visual size constant
+ return BaseStrokeWidth * scaleFactor;
+ }
+
public void UpdatePath()
{
if (MonitorData is not null && MonitorData.EdgeStates.Length > 0)
@@ -291,14 +396,26 @@
PanStartY = e.ClientY - TranslateY;
}
- private void HandleMouseMove(MouseEventArgs e)
+ private async Task HandleMouseMove(MouseEventArgs e)
{
+ // Calculate world coordinates of mouse
+ var svgRect = await JS.InvokeAsync("robotMonitor.getElementBoundingRect", SvgRef);
+ double mouseX = e.ClientX - svgRect.X;
+ double mouseY = e.ClientY - svgRect.Y;
+
+ // Convert to world coordinates
+ // World X = (mouseX - TranslateX) / (ZoomScale * BASE_PIXELS_PER_METER)
+ MouseWorldX = (mouseX - TranslateX) / (ZoomScale * BASE_PIXELS_PER_METER);
+ // World Y = -(mouseY - TranslateY) / (ZoomScale * BASE_PIXELS_PER_METER) (flip Y axis)
+ MouseWorldY = -(mouseY - TranslateY) / (ZoomScale * BASE_PIXELS_PER_METER);
+
if (IsPanning)
{
TranslateX = e.ClientX - PanStartX;
TranslateY = e.ClientY - PanStartY;
- StateHasChanged();
}
+
+ StateHasChanged();
}
private void HandleMouseUp(MouseEventArgs e)
@@ -309,6 +426,9 @@
private void HandleMouseLeave(MouseEventArgs e)
{
IsPanning = false;
+ MouseWorldX = null;
+ MouseWorldY = null;
+ StateHasChanged();
}
private async Task HandleWheel(WheelEventArgs e)
@@ -324,7 +444,7 @@
if (Math.Abs(ZoomScale - oldZoom) < 0.001) return;
// Zoom at mouse position
- var svgRect = await JS.InvokeAsync("getElementBoundingRect", SvgRef);
+ var svgRect = await JS.InvokeAsync("robotMonitor.getElementBoundingRect", SvgRef);
double mouseX = e.ClientX - svgRect.X;
double mouseY = e.ClientY - svgRect.Y;
diff --git a/RobotApp.Client/Pages/Components/Monitor/RobotMonitorView.razor.css b/RobotApp.Client/Pages/Components/Monitor/RobotMonitorView.razor.css
index 85f2893..21240f7 100644
--- a/RobotApp.Client/Pages/Components/Monitor/RobotMonitorView.razor.css
+++ b/RobotApp.Client/Pages/Components/Monitor/RobotMonitorView.razor.css
@@ -54,6 +54,18 @@
gap: 8px;
}
+.mouse-position-info {
+ color: #fff;
+ font-size: 14px;
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
+ padding: 4px 12px;
+ background-color: #3d3d3d;
+ border-radius: 4px;
+ display: flex;
+ align-items: center;
+ gap: 8px;
+}
+
.svg-container {
flex: 1;
overflow: hidden;
diff --git a/RobotApp.Client/Pages/Order/JsonOutputPanel.razor b/RobotApp.Client/Pages/Order/JsonOutputPanel.razor
index fbd2f25..11ba185 100644
--- a/RobotApp.Client/Pages/Order/JsonOutputPanel.razor
+++ b/RobotApp.Client/Pages/Order/JsonOutputPanel.razor
@@ -6,14 +6,14 @@
-
Import JSON
-
+ *@
{
+ const img = new Image();
+ img.onload = () => {
+ resolve({
+ Width: img.naturalWidth || img.width,
+ Height: img.naturalHeight || img.height
+ });
+ };
+ img.onerror = () => {
+ reject(new Error(`Failed to load image: ${imageUrl}`));
+ };
+ img.src = imageUrl;
+ });
}
};
@@ -65,3 +82,4 @@ window.robotMonitor = {
+
diff --git a/RobotApp/Components/App.razor b/RobotApp/Components/App.razor
index 05a1e6a..68a6103 100644
--- a/RobotApp/Components/App.razor
+++ b/RobotApp/Components/App.razor
@@ -42,6 +42,7 @@
+