@using MediatR
@using NexusReader.Application.Queries.Graph
@using Microsoft.JSInterop
@using NexusReader.UI.Shared.Services
@implements IAsyncDisposable
@inject IMediator Mediator
@inject IJSRuntime JS
@inject IFocusModeService FocusMode
@inject IKnowledgeGraphService GraphService
@inject IReaderInteractionService InteractionService
@if (GraphService.IsLoading || GraphService.CurrentGraphData == null)
{
Mapowanie relacji rozdziału...
}
else
{
}
@code {
[Parameter] public EventCallback OnNodeSelected { get; set; }
private string ContainerId = "d3-graph-container";
private IJSObjectReference? _module;
private DotNetObjectReference? _dotNetHelper;
protected override void OnInitialized()
{
FocusMode.OnFocusModeChanged += HandleFocusSimulation;
GraphService.OnGraphUpdated += HandleGraphUpdate;
GraphService.OnActiveNodeChanged += HandleActiveNodeChange;
GraphService.OnLoadingChanged += HandleLoadingChange;
}
private async Task HandleGraphUpdate()
{
if (_module == null) return;
if (GraphService.CurrentGraphData == null)
{
await _module.InvokeVoidAsync("clear");
}
else
{
await _module.InvokeVoidAsync("updateData", GraphService.CurrentGraphData);
}
await InvokeAsync(StateHasChanged);
}
private async Task HandleActiveNodeChange(string nodeId)
{
if (_module == null) return;
await _module.InvokeVoidAsync("setActiveNode", nodeId);
}
private async Task HandleLoadingChange(bool isLoading)
{
await InvokeAsync(StateHasChanged);
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await InitializeGraphAsync();
if (GraphService.CurrentGraphData != null)
{
await HandleGraphUpdate();
}
}
}
private async Task InitializeGraphAsync()
{
_module = await JS.InvokeAsync("import", "./_content/NexusReader.UI.Shared/js/knowledgeGraph.js");
_dotNetHelper = DotNetObjectReference.Create(this);
await _module.InvokeVoidAsync("mount", ContainerId, GraphService.CurrentGraphData, _dotNetHelper);
}
private async Task ZoomIn() => await (_module?.InvokeVoidAsync("zoomIn") ?? ValueTask.CompletedTask);
private async Task ZoomOut() => await (_module?.InvokeVoidAsync("zoomOut") ?? ValueTask.CompletedTask);
private async Task ZoomReset() => await (_module?.InvokeVoidAsync("zoomReset") ?? ValueTask.CompletedTask);
[JSInvokable]
public async Task OnNodeClicked(string nodeId)
{
await InteractionService.NotifyNodeSelected(nodeId);
if (OnNodeSelected.HasDelegate)
{
await OnNodeSelected.InvokeAsync(nodeId);
}
}
private async Task HandleFocusSimulation()
{
if (_module == null) return;
try
{
if (FocusMode.IsFocusModeActive)
await _module.InvokeVoidAsync("pause");
else
await _module.InvokeVoidAsync("resume");
}
catch { }
}
public async ValueTask DisposeAsync()
{
FocusMode.OnFocusModeChanged -= HandleFocusSimulation;
GraphService.OnGraphUpdated -= HandleGraphUpdate;
GraphService.OnActiveNodeChanged -= HandleActiveNodeChange;
GraphService.OnLoadingChanged -= HandleLoadingChange;
try
{
if (_module is not null)
{
await _module.InvokeVoidAsync("unmount", ContainerId);
await _module.DisposeAsync();
}
}
catch { }
_dotNetHelper?.Dispose();
}
}