@using RobotNet.WebApp.Robots.Components.Monitoring.Element @using System.Text.Json @inject IJSRuntime JSRuntime @inject ISnackbar Snackbar @inject IDialogService DialogService @inject IHttpClientFactory HttpFactory
@foreach (var zone in zones) { } @foreach (var edge in edges) { } @foreach (var edge in edges) { } @foreach (var node in nodes) { } @foreach (var element in elements) { }
Update Element @ElementUpdateModel.Name
@foreach (var property in ElementProperties) { @if (property.Type == typeof(int).ToString()) { if (int.TryParse(property.DefaultValue, out int value)) { } } else if (property.Type == typeof(double).ToString()) { if (double.TryParse(property.DefaultValue, out double value)) { } } else if (property.Type == typeof(bool).ToString()) { if (bool.TryParse(property.DefaultValue, out bool value)) { } } else if (property.Type == typeof(string).ToString()) { } }
Properties
Cancel Update
@code { [Parameter] public bool ShowGrid { get; set; } [Parameter] public bool ShowName { get; set; } [Parameter] public bool ShowPath { get; set; } [Parameter] public bool ShowLaser { get; set; } [Parameter] public bool ShowElement { get; set; } private MapMousePosition MapInfoRef = null!; private RobotPath RobotPathRef = null!; private RobotCurrentPath RobotCurrentPathRef = null!; private MapGrid MapGridRef = null!; private RobotLaserScaner RobotLaserScanerRef = null!; private DotNetObjectReference DotNetObj = null!; private ElementReference ViewContainerRef; private ElementReference ViewMovementRef; private ElementReference MapContainerRef; private ElementReference MapImageRef; private double ViewContainerRectX; private double ViewContainerRectY; private double ViewContainerRectWidth; private double ViewContainerRectHeight; private double ViewContainerRectTop; private double ViewContainerRectRight; private double ViewContainerRectBottom; private double ViewContainerRectLeft; private double CursorX; private double CursorY; private double ClientOriginX; private double ClientOriginY; private double Resolution = 1; private double OriginX; private double OriginY; private double ImageOriginY; private double ImageWidth; private double ImageHeight; private double Scale = 1; private double Left; private double Top; private double FitScale = 1; private double OldOriginY; private List edges = new(); private List nodes = new(); private List zones = new(); private List elements = new(); private MapRobotModel robots = new(); private bool IsFocusRobot = false; private string RobotSelectedId = ""; private bool updateElementVisble; private ElementUpdateModel ElementUpdateModel = new(); private List ElementProperties = []; protected override async Task OnAfterRenderAsync(bool firstRender) { await base.OnAfterRenderAsync(firstRender); if (!firstRender) return; DotNetObj = DotNetObjectReference.Create(this); await JSRuntime.InvokeVoidAsync("DOMCssLoaded"); await JSRuntime.InvokeVoidAsync("UpdateViewContainerRect", DotNetObj, ViewContainerRef, nameof(ViewContainerResize)); await JSRuntime.InvokeVoidAsync("ResizeObserverRegister", DotNetObj, ViewContainerRef, nameof(ViewContainerResize)); await JSRuntime.InvokeVoidAsync("AddEventListener", DotNetObj, ViewContainerRef, "click", nameof(ViewContainerClick)); await JSRuntime.InvokeVoidAsync("AddMouseMoveEventListener", DotNetObj, ViewContainerRef, nameof(MouseMoveOnMapContainer)); await JSRuntime.InvokeVoidAsync("AddMouseWheelEventListener", DotNetObj, MapContainerRef, nameof(MouseWheelOnMapContainer)); await JSRuntime.InvokeVoidAsync("AddTouchMoveEventListener", DotNetObj, ViewContainerRef, nameof(TouchMoveOnMapContainer)); } public async Task LoadMap(MapDataDto? mapData) { if (mapData == null) { nodes.Clear(); edges.Clear(); zones.Clear(); elements.Clear(); robots.ReplaceAll([]); RobotCurrentPathRef.UpdatePath([]); RobotPathRef.UpdatePath([]); Resolution = 1.0; OriginY = 0; OriginX = 0; OldOriginY = 0; ImageOriginY = 0; ImageHeight = 0; ImageWidth = 0; MapGridRef.Resize(OriginX, OriginY, ImageHeight, ImageWidth); await JSRuntime.InvokeVoidAsync("SetMapSvgConfig", MapContainerRef, ImageWidth, ImageHeight, OriginX, 1.0); await JSRuntime.InvokeVoidAsync("SetImageAttribute", MapImageRef, ImageWidth, ImageHeight, OriginX, OriginY, ""); } else { nodes = [.. mapData.Nodes.Select(node => new NodeModel(node))]; edges = [.. mapData.Edges.Select(edge => new EdgeModel(edge, nodes.First(n => n.Id == edge.StartNodeId), nodes.First(n => n.Id == edge.EndNodeId)))]; zones = [.. mapData.Zones.Select(zone => new ZoneModel(zone))]; elements = [.. mapData.Elements.Select(element => new ElementModel(element, nodes.First(n => n.Id == element.NodeId)))]; Resolution = mapData.Resolution; OldOriginY = mapData.OriginY; OriginY = -mapData.ImageHeight * Resolution - mapData.OriginY; OriginX = mapData.OriginX; ImageOriginY = mapData.OriginY; ImageHeight = mapData.ImageHeight * Resolution; ImageWidth = mapData.ImageWidth * Resolution; MapGridRef.Resize(OriginX, OriginY, ImageHeight, ImageWidth); using var Http = HttpFactory.CreateClient("MapManagerAPI"); await JSRuntime.InvokeVoidAsync("SetMapSvgConfig", MapContainerRef, ImageWidth, ImageHeight, OriginX, mapData.OriginY); await JSRuntime.InvokeVoidAsync("SetImageAttribute", MapImageRef, ImageWidth, ImageHeight, OriginX, OriginY, $"{Http.BaseAddress}api/images/map/{mapData.Id}"); await JSRuntime.InvokeVoidAsync("UpdateViewContainerRect", DotNetObj, ViewContainerRef, nameof(ViewContainerResize)); await ScaleFitContentAsync(); } StateHasChanged(); } public async Task ScaleFitContentAsync() { Scale = FitScale; await SetViewMovement((ViewContainerRectWidth - ImageWidth * Scale) / 2, (ViewContainerRectHeight - ImageHeight * Scale) / 2); await JSRuntime.InvokeVoidAsync("SetMapSvgRect", MapContainerRef, ImageWidth * Scale, ImageHeight * Scale); } private async Task SetViewMovement(double left, double top) { Top = top; Left = left; ClientOriginX = ViewContainerRectLeft + Left - OriginX * Scale; ClientOriginY = ViewContainerRectTop + Top - OriginY * Scale; await JSRuntime.InvokeVoidAsync("SetMapMovement", ViewMovementRef, Top, Left); } public async Task ScaleZoom(double deltaY) { if (deltaY > 0) { if (Scale >= FitScale * 20) return; } else { if (Scale <= FitScale / 2) return; } double oldScale = Scale; Scale += deltaY; double centerXBefore = ((ViewContainerRectLeft + ViewContainerRectWidth / 2) - ClientOriginX) / oldScale - OriginX; double centerYBefore = (ClientOriginY - (ViewContainerRectHeight / 2 + ViewContainerRectTop)) / oldScale - OldOriginY; await SetViewMovement(Left - centerXBefore * deltaY, Top - (ImageHeight - centerYBefore) * deltaY); await JSRuntime.InvokeVoidAsync("SetMapSvgRect", MapContainerRef, ImageWidth * Scale, ImageHeight * Scale); } [JSInvokable] public void ViewContainerResize(double x, double y, double width, double height, double top, double right, double bottom, double left) { ViewContainerRectX = x; ViewContainerRectY = y; ViewContainerRectWidth = width; ViewContainerRectHeight = height; ViewContainerRectTop = top; ViewContainerRectRight = right; ViewContainerRectBottom = bottom; ViewContainerRectLeft = left; ClientOriginX = ViewContainerRectLeft + Left - OriginX * Scale; ClientOriginY = ViewContainerRectTop + Top - OriginY * Scale; FitScale = Math.Min(ViewContainerRectWidth / ImageWidth, ViewContainerRectHeight / ImageHeight); } [JSInvokable] public async Task TouchMoveOnMapContainer(double clientX, double clientY, int touchCount, double movementX, double movementY) { CursorX = (clientX - ClientOriginX) / Scale; CursorY = (ClientOriginY - clientY) / Scale; MapInfoRef.Update(CursorX, CursorY); if (touchCount == 1) await SetViewMovement(Left + movementX, Top + movementY); } [JSInvokable] public async Task MouseWheelOnMapContainer(double deltaY, double offsetX, double offsetY) { double scaleChange; if (deltaY > 0) { if (Scale <= FitScale / 2) return; scaleChange = Scale > FitScale ? -(Scale / FitScale) : -0.1; } else { if (Scale >= FitScale * 100) return; scaleChange = Scale < FitScale ? 0.5 : (Scale / FitScale); } double oldScale = Scale; Scale += scaleChange; await JSRuntime.InvokeVoidAsync("SetMapSvgRect", MapContainerRef, ImageWidth * Scale, ImageHeight * Scale); double mouseX = CursorX - OriginX; double mouseY = CursorY - OldOriginY; await SetViewMovement(Left - mouseX * scaleChange, Top - (ImageHeight - mouseY) * scaleChange); } [JSInvokable] public async Task ViewContainerClick() => await ViewContainerRef.FocusAsync(); [JSInvokable] public async Task MouseMoveOnMapContainer(double clientX, double clientY, long buttons, bool ctrlKey, double movementX, double movementY) { CursorX = (clientX - ClientOriginX) / Scale; CursorY = (ClientOriginY - clientY) / Scale; MapInfoRef.Update(CursorX, CursorY); if (IsFocusRobot) return; switch (buttons) { case 4: await SetViewMovement(Left + movementX, Top + movementY); break; } } public void LoadRobots(IEnumerable robotDtos) { if (robotDtos.Any()) { var robotModel = robotDtos.Select(robot => new RobotVisualizationModel() { RobotId = robot.RobotId, RobotName = robot.Name, X = robot.AgvPosition.X, Y = robot.AgvPosition.Y, Theta = robot.AgvPosition.Theta, }).ToArray(); robots.ReplaceAll(robotModel); } else robots.ReplaceAll([]); StateHasChanged(); } public void RobotSelectedChange(string robotId) { if (robotId != RobotSelectedId) RobotSelectedId = robotId; } public void FocusRobot(bool value) => IsFocusRobot = value; public async Task FocusRobotAsync() { var robot = robots.FirstOrDefault(r => r.RobotId == RobotSelectedId); if (robot is null) return; double mapX = (ViewContainerRectWidth - ImageWidth * Scale) / 2 + ((ImageWidth / 2 + OriginX) * Scale) - robot.X * Scale; double mapY = (ViewContainerRectHeight - ImageHeight * Scale) / 2 + ((ImageHeight / 2 + OriginY) * Scale) + robot.Y * Scale; await SetViewMovement(mapX, mapY); } public async Task SetRobotPosition(List robotStates) { foreach (var robot in robotStates) { var robotModel = robots.FirstOrDefault(rm => rm.RobotId == robot.RobotId); if (robotModel is not null) { robotModel.Update(robot.AgvPosition.X, robot.AgvPosition.Y, robot.AgvPosition.Theta, robot.Loads); if (IsFocusRobot && robot.RobotId == RobotSelectedId) await FocusRobotAsync(); } else { robots.Add(new() { RobotId = robot.RobotId, RobotName = robot.Name, X = robot.AgvPosition.X, Y = robot.AgvPosition.Y, Theta = robot.AgvPosition.Theta, Loads = robot.Loads }); StateHasChanged(); } if (robot.RobotId == RobotSelectedId) { RobotPathRef.UpdatePath([.. robot.Navigation.RobotPath]); RobotCurrentPathRef.UpdatePath([.. robot.Navigation.RobotBasePath]); RobotLaserScanerRef.SetData(robot.Navigation.LaserScaner); } } } public void ElementStateUpdated(IEnumerable elementsState) { foreach (var elmenet in elementsState) { var elemetModel = elements.FirstOrDefault(e => e.Id == elmenet.Id); if (elemetModel is not null) { elemetModel.Update(elmenet); } else { var node = nodes.FirstOrDefault(n => n.Id == elmenet.NodeId); if (node is not null) elements.Add(new ElementModel(elmenet, node)); } } StateHasChanged(); } private void DefaultIntValueChanged(Guid id, int value) { var property = ElementProperties.FirstOrDefault(p => p.Id == id); if (property is null) return; property.DefaultValue = value.ToString(); } private void DefaultDoubleValueChanged(Guid id, double value) { var property = ElementProperties.FirstOrDefault(p => p.Id == id); if (property is null) return; property.DefaultValue = value.ToString(); } private void DefaultBooleanValueChanged(Guid id, bool value) { var property = ElementProperties.FirstOrDefault(p => p.Id == id); if (property is null) return; property.DefaultValue = value.ToString(); } private void ElementDoubleClick(ElementModel model) { ElementUpdateModel.Id = model.Id; ElementUpdateModel.Name = model.Name; ElementUpdateModel.IsOpen = model.IsOpen; ElementUpdateModel.OffsetX = model.OffsetX; ElementUpdateModel.OffsetY = model.OffsetY; ElementUpdateModel.Content = model.Content; if (model is not null && !string.IsNullOrEmpty(model.Content)) { var properties = JsonSerializer.Deserialize>(model.Content, JsonOptionExtends.Read); if (properties is not null) ElementProperties = [.. properties]; } updateElementVisble = true; StateHasChanged(); } private async Task UpdateElement() { var selectedElement = elements.FirstOrDefault(e => e.Id == ElementUpdateModel.Id); if (selectedElement is null) return; using var Http = HttpFactory.CreateClient("MapManagerAPI"); var result = await (await Http.PutAsJsonAsync($"api/Elements", new ElementUpdateModel() { Id = ElementUpdateModel.Id, Name = ElementUpdateModel.Name, IsOpen = ElementUpdateModel.IsOpen, OffsetX = ElementUpdateModel.OffsetX, OffsetY = ElementUpdateModel.OffsetY, Content = JsonSerializer.Serialize(ElementProperties, JsonOptionExtends.Write), })).Content.ReadFromJsonAsync>(); if (result == null) Snackbar.Add("Lỗi giao tiếp với hệ thống", Severity.Error); else if (!result.IsSuccess) Snackbar.Add(result.Message, Severity.Error); else if (result.Data is null) Snackbar.Add("Lỗi dữ liệu", Severity.Error); else { selectedElement.Update(result.Data); Snackbar.Add("Cập nhật thành công", Severity.Success); } updateElementVisble = false; StateHasChanged(); } }